4
>> $start_dt = new DateTime()
DateTime::__set_state(array(
   'date' => '2012-04-11 08:34:01',
   'timezone_type' => 3,
   'timezone' => 'America/Los_Angeles',
))
>> $end_dt = new DateTime()
DateTime::__set_state(array(
   'date' => '2012-04-11 08:34:06',
   'timezone_type' => 3,
   'timezone' => 'America/Los_Angeles',
))
>> $start_dt->setTimestamp(strtotime('31-Jan-2012'))
DateTime::__set_state(array(
   'date' => '2012-01-31 00:00:00',
   'timezone_type' => 3,
   'timezone' => 'America/Los_Angeles',
))
>> $end_dt->setTimestamp(strtotime('1-Mar-2012'))
DateTime::__set_state(array(
   'date' => '2012-03-01 00:00:00',
   'timezone_type' => 3,
   'timezone' => 'America/Los_Angeles',
))
>> $interval = $start_dt->diff($end_dt)
DateInterval::__set_state(array(
   'y' => 0,
   'm' => 0,
   'd' => 30,
   'h' => 0,
   'i' => 0,
   's' => 0,
   'invert' => 0,
   'days' => 30,
))
>> $interval->format('%mm %dd')
'0m 30d'

即,不到一个月31-Jan-2012的产量!1-Mar-2012我希望输出为 1 个月 1 天。二月的天数无关紧要;这就是使用时间库的重点——它应该处理这些事情。WolframAlpha 同意

我应该向 PHP 提交错误吗?是否有破解/修复/解决方法可以让几个月按预期工作?

4

2 回答 2

6

更新的答案

的这种行为DateTime::diff当然是出乎意料的,但这不是错误。简而言之,diff返回年、月、日等,如果你这样做了

$end_ts = strtotime('+$y years +$m months +$d days' /* etc */, $start_ts);

您将取回与结束原始结束日期相对应的时间戳。

这些添加是“盲目”执行的,然后应用日期更正(例如,1 月 31 日 + 1 个月将是 2 月 31 日,根据年份更正为 3 月 2 日或 3 月 3 日)。在这个具体的例子中,你甚至不能添加一个月,正如salathe 还解释的那样。

于 2012-04-11T15:46:30.723 回答
5

我应该向 PHP 提交错误吗?

不。

间隔的“月份”部分意味着开始日期的月份部分可以增加那么多个月。PHP 中的行为,获取您的开始日期31-Jan-2012并增加月份(字面意思是,31-Feb-2012)然后更正一个有效日期(PHP 为您执行此操作)将给出02-Mar-2012晚于您正在使用的目标日期。

为了证明这一点,请取您的开始日期并在几个月内添加n 个月以查看行为

31-Jan-2012 (Interval)
02-Mar-2012 (P1M)
31-Mar-2012 (P2M)
01-May-2012 (P3M)
31-May-2012 (P4M)
01-Jul-2012 (P5M)

您可以看到月份正在递增,然后调整为有效日期。

于 2012-04-11T15:52:26.083 回答