Skip to content
Advertisement

PHP’s date_diff() is behaving unexpectedly

It’s probably just me being dumb, but …

<?php
   $startDate = date_create('2019-11-01');
   $endDate = date_create('2019-12-01');
       
    $interval = date_diff($startDate, $endDate);
    
   var_dump($interval);       
?>

in PHPfiddle gives (as expected):

object(DateInterval)#3 (15)
{ [“y”]=> int(0)
[“m”]=> int(1) <=== this is what gives me problems on my local machine
[“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”]=> int(30)
[“special_type”]=> int(0)
[“special_amount”]=> int(0)
[“have_weekday_relative”]=> int(0)
[“have_special_relative”]=> int(0) }

Check out the value of m, which is number of months.

However, on my local machine, the same code gives:

class DateInterval#4 (16) {
  public $y =>
  int(0)
  public $m =>
  int(0)                          <======  why ??!!
  public $d =>
  int(30)
  public $h =>
  int(0)
  public $i =>
  int(0)
  public $s =>
  int(0)
  public $f =>
  double(0)
  public $weekday =>
  int(0)
  public $weekday_behavior =>
  int(0)
  public $first_last_day_of =>
  int(0)
  public $invert =>
  int(0)
  public $days =>
  int(30)
  public $special_type =>
  int(0)
  public $special_amount =>
  int(0)
  public $have_weekday_relative =>
  int(0)
  public $have_special_relative =>
  int(0)
}

OK, I will concede that is is 30 days, but the answer that I was looking for was 1 month, and $interval->m is zer0.

What am I missing? I don’t know what version of PHP the PHPfiddle web site uses, but I am using 7.3.11 locally.

Advertisement

Answer

Probably the difference is in the timezone.

try this:

<?php
   date_default_timezone_set('UTC');

   $startDate = date_create('2019-11-01');
   $endDate = date_create('2019-12-01');
       
   $interval = date_diff($startDate, $endDate);
    
   var_dump($interval);  
/*
object(DateInterval)#3 (16) {
  ["y"]=>
  int(0)
  ["m"]=>
  int(1)
  ...
*/

also try this:

<?php
   $startDate = date_create('2019-11-01 23:00');
   $endDate = date_create('2019-12-01 23:00');
       
   $interval = date_diff($startDate, $endDate);
    
   var_dump($interval);       
   /* outputs the same ["m"]=> int(1) as above */

Probably date_diff looking for a difference between UTC timestamp and you have the default timezone on your PHP set to some positive value.

Let’s say you have some default timezone which is UTC+02:00 therefore date_create('2019-11-01') actually makes a date 2019-10-31 22:00:00 (UTC) and date_create('2019-12-01') actually makes a date 2019-11-30 22:00:00 (UTC)

now you can see they have no whole month difference.

But you can catch another funny effect:

<?php
   //assuming your timezone is UTC+something
   $startDate = date_create('2019-10-31'); // creates a date 2019-10-30 XX:00 UTC
   $endDate = date_create('2019-12-01');   // creates a date 2019-11-30 XX:00 UTC
       
   $interval = date_diff($startDate, $endDate);
    
   var_dump($interval);       

/*
object(DateInterval)#3 (16) {
  ["y"]=>
  int(0)  
  ["m"]=>
  int(1)   sic(!)
  ["d"]=>
  int(0)   sic(!)
*/

Also you may have unexpected result if your timezone has the daylight saving.

<?php
   // Germany has the daylight saving shift at last Sunday of March and October.
   date_default_timezone_set('Europe/Berlin'); 

   $startDate = date_create('2020-03-28 03:00');
   $endDate = date_create('2020-03-29 02:00');

   $interval = date_diff($startDate, $endDate);
    
   var_dump($interval);  //   ["d"]=>  int(1)  ["h"]=>  int(0)

   
   
   $startDate = date_create('2020-03-28 03:00');
   $endDate = date_create('2020-03-29 03:00');

   $interval = date_diff($startDate, $endDate); 

   var_dump($interval); //   ["d"]=>  int(1)  ["h"]=>  int(0)


   $startDate = date_create('2020-03-28 03:00');
   $endDate = date_create('2020-03-28 03:00'); // the same
   $endDate->modify('+23 hour');

   $interval = date_diff($startDate, $endDate);
    
   var_dump($interval);  //   ["d"]=>  int(1)  ["h"]=>  int(0)

PHPFiddle has the default timezone set to UTC, therefore it gives one month difference by default.

To avoid that, just perform all date calculations in UTC from the beginning:

<?php
   $timeZone = new DateTimeZone('UTC');

   $startDate = new DateTime('2019-10-31', $timeZone);
   $endDate = new DateTime('2019-12-01', $timeZone);
       
   $interval = date_diff($startDate, $endDate);
    
   var_dump($interval);       
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement