Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a bug in PHP's DateTime:diff?

>> $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?

like image 630
mpen Avatar asked Dec 20 '22 23:12

mpen


1 Answers

Updated answer

This behavior of DateTime::diff is certainly unexpected, but it's not a bug. In a nutshell, diff returns years, months, days etc such that if you did

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

you would get back the timestamp that corresponds to end original end date.

These additions are performed "blindly" and then date correction applies (e.g. Jan 31 + 1 month would be Feb 31, corrected to Mar 2 or Mar 3 depending on the year). In this specific example you cannot add even one month as salathe also explains.

like image 171
Jon Avatar answered Jan 04 '23 01:01

Jon