创建PHP DatePeriod与每月的间隔


Create PHP DatePeriod with monthly intervals

下面的代码根据用户输入创建一个PHP DatePeriod对象。循环的第一次迭代运行,但第二次迭代返回这个错误:PHP Fatal error: Call to a member function format() on a non-object。我看不出是什么原因导致错误。

我希望使用它来填充一个包含不规则重复日期的数组。ie。"本月第二个星期日"、"本月最后一个星期五"。

$raw_dates['starting'] = DateTime::createFromFormat( 'Ymd', $starting_date );
$raw_dates['ending'] = DateTime::createFromFormat( 'Ymd', $ending_date );
if ( 'Monthly' == $frequency ) {
    $recurances = $raw_dates['starting']->diff($raw_dates['ending']);
    $recurances = $recurances->m;
    $i = 'P1M';
    $interval = new DateInterval( $i );
    $period = new DatePeriod( $raw_dates['starting'], $interval, $recurances );
    $string = $monthly_recurring_week.' '.$monthly_recurring_day.' of ';
    foreach ( $period as $date ) {
        $string .= $date->format( 'F Y');
        $occurance = strtotime( $string );
        $raw_occurance = DateTime::createFromFormat( 'U', $occurance );
        $finished_date = $raw_occurance->format( 'Ymd' );
        $occurances[] = array(
            'sm_set_starts' => $finished_date,
            'sm_set_ends' => $finished_date
        );
    }
}

这行是在第二次迭代时抛出错误的行:$finished_date = $raw_occurance->format( 'Ymd' );但我认为可能更早与我的DatePeriod对象。

这是DatePeriod对象的转储:

object(DatePeriod)#51 (6) {
  ["start"]=>
  object(DateTime)#53 (3) {
    ["date"]=>
    string(26) "2015-07-01 14:34:01.000000"
    ["timezone_type"]=>
    int(3)
    ["timezone"]=>
    string(3) "UTC"
  }
  ["current"]=>
  NULL
  ["end"]=>
  NULL
  ["interval"]=>
  object(DateInterval)#55 (15) {
    ["y"]=>
    int(0)
    ["m"]=>
    int(1)
    ["d"]=>
    int(0)
    ["h"]=>
    int(0)
    ["i"]=>
    int(0)
    ["s"]=>
    int(0)
    ["weekday"]=>
    int(0)
    ["weekday_behavior"]=>
    int(0)
    ["first_last_day_of"]=>
    int(0)
    ["invert"]=>
    int(0)
    ["days"]=>
    bool(false)
    ["special_type"]=>
    int(0)
    ["special_amount"]=>
    int(0)
    ["have_weekday_relative"]=>
    int(0)
    ["have_special_relative"]=>
    int(0)
  }
  ["recurrences"]=>
  int(3)
  ["include_start_date"]=>
  bool(true)
}

根据John Conde的建议使用DateTime,并根据Sverri M Olsen对这个SO问题的回答,我发现了DateInterval:createFromDateString。

这是这个问题的工作代码

if ( 'Monthly' == $frequency ) {
    $string = $monthly_recurring_week.' '.$monthly_recurring_day.' of next month';
    $interval = DateInterval::createFromDateString( $string );
    $period   = new DatePeriod($raw_dates['starting'], $interval, $raw_dates['ending'], DatePeriod::EXCLUDE_START_DATE);
    foreach($period as $time) {
        $occurances[] = array(
            'sm_set_starts' => $time->format( 'Ymd' ),
            'sm_set_ends' => $time->format( 'Ymd' )
        );
    }
}

我认为值得注意的是,当循环遍历DatePeriod对象时,日期字符串的"下个月"部分相对于当前间隔,而不是开始日期,这是我在原始文章中所做的。