Php 二月份

Php 二月份,php,recurring,Php,Recurring,我试图根据日历日期范围计算每月重复发生的事件。然而,当某个事件发生在2月29日时,我偶然发现了一个问题,即2月(28天)的计算。希望一些专家能给我一些指点,因为我尝试在没有帮助的情况下四处搜索 为了便于直接作为脚本运行,我包含了以下代码。1月范围工作正常,这给了我两个属于该范围的日期: // JANUARY 2013 Range (Working) 2012-12-29 2013-01-29 但如果取消注释二月范围,它将开始输出: 2013-01-29 // This is correct 2

我试图根据日历日期范围计算每月重复发生的事件。然而,当某个事件发生在2月29日时,我偶然发现了一个问题,即2月(28天)的计算。希望一些专家能给我一些指点,因为我尝试在没有帮助的情况下四处搜索

为了便于直接作为脚本运行,我包含了以下代码。
1月
范围工作正常,这给了我两个属于该范围的日期:

// JANUARY 2013 Range (Working)
2012-12-29
2013-01-29
但如果取消注释二月范围,它将开始输出:

2013-01-29 // This is correct
2013-02-28 // This is the date which I want to ignore because its not on the 29th.
如果您取消对
April
范围的注释,它将开始什么也不输出。它应该输出一个日期
2013-04-29
。因此,我想问题在于计算

<?php

// Start Calendar Range

// JANUARY 2013 Range (Working)
$rangeStart = new DateTime( '2012-12-30' );
$rangeEnd   = new DateTime( '2013-02-03' );

// FEBRUARY 2013 Range (Not Working)
//$rangeStart = new DateTime( '2013-01-27' );
//$rangeEnd   = new DateTime( '2013-03-03' );

// APRIL 2013 Range (Not Working)
//$rangeStart = new DateTime( '2013-03-31' );
//$rangeEnd   = new DateTime( '2013-04-05' );

// MAY 2013 Range (Working)
//$rangeStart = new DateTime( '2013-04-28' );
//$rangeEnd   = new DateTime( '2013-06-02' );

// Event date start
$eventStart = new DateTime( '2012-10-29' );
$recurTimes = 1;

// Loop thru the days of month
while( $rangeStart->format('U') <= $rangeEnd->format('U') ) {
    $currView = mktime( 0, 0, 0, $rangeStart->format('m'), $eventStart->format('d'), $rangeStart->format('Y') );
    $interval = round(($currView-$eventStart->format('U')) / 60 / 60 / 24 / 30);

    $monthsAway = $eventStart->format('m')+$interval;
    $recurMonth = $eventStart->format('m')%$recurTimes;

    if( $monthsAway%$recurTimes == $recurMonth ) {
        $nextRecur = getNextRecur( $eventStart->format('U'), $interval );
        echo date( 'Y-m-d', $nextRecur ) . '<br />';
    }
    $rangeStart->modify('+1 month');
}


// function to add 1 month with leap year in consideration
function getNextRecur( $baseTime=null, $months=1 ) {
    if( is_null( $baseTime ) ) $baseTime = time( );
    $xMonths = strtotime( '+' . $months . ' months', $baseTime );
    $before = (int)date( 'm', $baseTime )+12*(int)date( 'Y', $baseTime );
    $after  = (int)date( 'm', $xMonths )+12*(int)date( 'Y', $xMonths );
    if( $after > $months+$before ) {
        $xMonths = strtotime( date('Ym01His', $xMonths) . ' -1 day' );
    }
    return $xMonths;
}
?>

也许你这样做是有原因的,但在我看来,这有点离谱。 我们都知道,所有的月份都是以天为单位的,二月是奇数。 所以我希望你能从这个角度来看

我并没有考虑我将如何“准确地”完成它,但我会将它简化为只在2月工作。 也许你可以先做一次年检,看看是不是闰年。然后让您的代码在插入2月的日期后执行所需的操作。

您可以尝试

例1

$rangeStart = new DateTime('2012-12-30');
$rangeEnd = new DateTime('2013-02-03');
$eventStart = new DateTime('2012-10-29');
var_dump(getRange($rangeStart, $rangeEnd, $eventStart));
输出

array
  0 => string '2013-01-29' (length=10)
例2

$rangeStart = new DateTime('2012-01-27');
$rangeEnd = new DateTime('2013-03-03');
$eventStart = new DateTime('2012-10-29');
var_dump(getRange($rangeStart, $rangeEnd, $eventStart));
输出

array
  0 => string '2012-10-29' (length=10)
  1 => string '2012-11-29' (length=10)
  2 => string '2012-12-29' (length=10)
  3 => string '2013-01-29' (length=10) 
使用的功能

function getRange($rangeStart, $rangeEnd, $eventStart, $fixedDay = 29) {
    $lastStart = clone $rangeStart;
    $rangeStart->setDate($eventStart->format('Y'), $eventStart->format('m'), $eventStart->format('d'));
    $list = array();
    while ( $rangeStart <= $rangeEnd ) {
        if ($rangeStart > $rangeEnd)
            break;
        if ($rangeStart->format('m') == 2 || $rangeStart < $lastStart) {
            $rangeStart->modify('+1 month');
            $rangeStart->setDate($rangeStart->format('Y'), $rangeStart->format('m'), $fixedDay);
            continue;
        }
        $list[] = $rangeStart->format("Y-m-d");
        $rangeStart->modify('+1 month');
        $rangeStart->setDate($rangeStart->format('Y'), $rangeStart->format('m'), $fixedDay);
    }
    return $list;
}
函数getRange($rangeStart,$rangeEnd,$eventStart,$fixedDay=29){ $lastStart=克隆$rangeStart; $rangeStart->setDate($eventStart->格式('Y'),$eventStart->格式('m'),$eventStart->格式('d'); $list=array(); 而($rangeStart$rangeEnd) 打破 如果($rangeStart->format('m')==2 | |$rangeStart<$lastStart){ $rangeStart->修改(“+1个月”); $rangeStart->setDate($rangeStart->格式('Y'),$rangeStart->格式('m'),$fixedDay); 继续; } $list[]=$rangeStart->格式(“Y-m-d”); $rangeStart->修改(“+1个月”); $rangeStart->setDate($rangeStart->格式('Y'),$rangeStart->格式('m'),$fixedDay); } 返回$list; }
测试了刚刚返回的代码。。2012-12-29 , 2013-01-29 .. 我想先关注一下代码的目标。。。什么是偶数间隔?为什么选择用整数计算?您需要取消对2013年2月范围的注释,它将输出2013-01-29和2013-02-28。2013-02-28是我希望忽略的日期。最初我使用的是ceil,但我在2月份也遇到了28天的问题。所以目前只有一轮似乎没有给问题。我想我现在明白了。。。。如果我错了,请纠正我。。应该显示
2013-02-28
而不是
2013-03-01
对吗?不,我只想在每个月的29日显示活动。对于二月的情况,我希望它跳过,因为它没有第29个?这很容易。。但是你的代码让它变得复杂。。。。你想输出每个月的日期吗?这比在2月检查更复杂,因为如果不考虑2月的计算,就像我在第一篇文章中发布的那样,它会影响4月也不会输出事件。如果你只是不评论2月、3月、4月等等,最后一个变量值将覆盖最早的值。你是如何保持它们的独特性和连续性的?因为我正在做这样的工作,当你每月滚动时,范围可能从10月30日到11月10日或11月28日到12月8日开始。谢谢爸爸。但是,如果你尝试4月份的范围,它仍然不能提供任何输出。有什么想法吗?还有三月份,它给我的是2013-01-29,而不是2013-03-291。我总是跳过二月,即使你很生气。。您的活动日期也会影响输出…很抱歉,我在第一篇文章中没有包括三月范围。三月范围为$rangeStart=新日期时间('2013-02-24')$rangeEnd=新日期时间('2013-03-07')@袁芬:好的,让我来测试一下。。等等