>> $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'
i.e., 31-Jan-2012 to 1-Mar-2012 yields less than a month! I’d expect the output to be 1 month, 1 day. It shouldn’t matter the number of days in February; that’s the point of using a time library — it’s supposed to handle these things. WolframAlpha agrees.
Should I file a bug to PHP? Is there a hack/fix/workaround to get months to work as expected?
No.
The “month” part of the interval means that the month part of the start date can be incremented by that many months. The behaviour in PHP, taking your start date of
31-Jan-2012and incrementing the month (literally,31-Feb-2012) and then correcting for a valid date (PHP does this for you) would give02-Mar-2012which is later than the target date that you are working with.To demonstrate this, take your start date and add n months for a few months to see the behaviour.
You can see that the month is being incremented, then adjusted to make a valid date.