Skip to content

DateTime::diff miscalculation is same time zone of different type #8730

Closed

Description

@jabelli

Description

Something appears amiss when DateTime::diff is used on two dates in the same time zone with different time zone types in DST
Possibly related to #81263
The following code:

<?php

$foo = new DateTime('2022-06-08 09:15:00', new DateTimeZone('-04:00'));
$bar = new DateTime('2022-06-08 09:15:00', new DateTimeZone('US/Eastern'));
var_dump($foo->diff($bar));

Resulted in this output:

  ["y"]=>
  int(-1)
  ["m"]=>
  int(11)
  ["d"]=>
  int(30)
  ["h"]=>
  int(23)
  ["i"]=>
  int(0)
  ["s"]=>
  int(0)
  ["f"]=>
  float(0)
  ["weekday"]=>
  int(0)
  ["weekday_behavior"]=>
  int(0)
  ["first_last_day_of"]=>
  int(0)
  ["invert"]=>
  int(0)
  ["days"]=>
  int(0)
  ["special_type"]=>
  int(0)
  ["special_amount"]=>
  int(0)
  ["have_weekday_relative"]=>
  int(0)
  ["have_special_relative"]=>
  int(0)
}

But I expected this output instead:

  ["y"]=>
  int(0)
  ["m"]=>
  int(0)
  ["d"]=>
  int(0)
  ["h"]=>
  int(0)
  ["i"]=>
  int(0)
  ["s"]=>
  int(0)
  ["f"]=>
  float(0)
  ["weekday"]=>
  int(0)
  ["weekday_behavior"]=>
  int(0)
  ["first_last_day_of"]=>
  int(0)
  ["invert"]=>
  int(0)
  ["days"]=>
  int(0)
  ["special_type"]=>
  int(0)
  ["special_amount"]=>
  int(0)
  ["have_weekday_relative"]=>
  int(0)
  ["have_special_relative"]=>
  int(0)
}

Linky

If you change the month to 01, you get the expected difference of 0.

PHP Version

PHP 8.1.6

Operating System

Windows 10

Activity

  1. hormus commented on Jun 12, 2022

    @hormus

    Since php 8.1.0 diff compares time zone type equality, in some circumstances although type 1 (numeric time zone) or type 3 (literal time zone) may produce a date with daylight saving time setting. (it means that although type 3 time zone converted to numerical sequence of seconds is exactly the same as type 1 time zone, as php decides whether to consider daylight saving time or not).

    https://wiki.php.net/rfc/datetime_and_daylight_saving_time

    It is difficult to document and too much information is confusing, certainly a good encoding is to use the same type timezone for the two date objects requested by diff.
    This change https://bugs.php.net/bug.php?id=81458

    $foo is big to $bar, inverter to $bar->diff($foo));

    <?php
    
    date_default_timezone_set('America/New_York');
    $foo = new DateTime('2022-06-08 09:15:00', new DateTimeZone('-04:00'));
    $bar = new DateTime('2022-06-08 09:15:00', new DateTimeZone('America/New_York'));
    var_dump($foo->format('U'), $bar->format('U'), $bar->diff($foo));
    /*string(10) "1654694100"
    string(10) "1654694100"
    object(DateInterval)#3 (16) {
      ["y"]=>
      int(0)
      ["m"]=>
      int(0)
      ["d"]=>
      int(0)
      ["h"]=>
      int(1)
      ["i"]=>
      int(0)
      ["s"]=>
      int(0)
      ["f"]=>
      float(0)
      ["weekday"]=>
      int(0)
      ["weekday_behavior"]=>
      int(0)
      ["first_last_day_of"]=>
      int(0)
      ["invert"]=>
      int(0)
      ["days"]=>
      int(0)
      ["special_type"]=>
      int(0)
      ["special_amount"]=>
      int(0)
      ["have_weekday_relative"]=>
      int(0)
      ["have_special_relative"]=>
      int(0)
    }*/
    ?>

    Note* US/Eastern https://www.php.net/manual/en/timezones.others.php

    before php 8.1 the comparison was for the date represented by the conversion to UTC

    <?php
    
    date_default_timezone_set('America/New_York');
    $foo = new DateTime('2022-06-08 09:15:00', new DateTimeZone('-04:00'));
    $bar = new DateTime('2022-06-08 09:15:00', new DateTimeZone('America/New_York'));
    var_dump($foo->format('U'), $bar->format('U'), $bar->diff($foo)); //Before php 8.1.0 2022-06-08 13:15:00 - 2022-06-08 13:15:00 = 0
    
    $foo = new DateTime('2022-06-08 09:15:00', new DateTimeZone('America/New_York'));
    $bar = new DateTime('2022-06-08 09:15:00', new DateTimeZone('America/New_York'));
    var_dump($foo->format('U'), $bar->format('U'), $bar->diff($foo)); //from php 8.1.0 2022-06-08 9:15:00 - 2022-06-08 9:15:00 = 0
    
    ?>
  2. derickr commented on Jun 17, 2022

    @derickr
    Member

    Fixed in timelib: derickr/timelib#128, and the fix will make it into PHP once timelib gets merged again.

  3. ToshY commented on Jul 20, 2022

    @ToshY

    @derickr Could you give an estimation on when this (timelib fix) actually gets merged?

  4. added a commit that references this issue on Jul 21, 2022
    cc9c577
  5. derickr commented on Jul 21, 2022

    @derickr
    Member

    Just now :-)

  6. jabelli commented on Jul 21, 2022

    @jabelli
    Author

    Create new for 8.2 or reopen this one? I just tested 8.2β1:

    object(DateInterval)#3 (10) {
      ["y"]=>
      int(-1)
      ["m"]=>
      int(11)
      ["d"]=>
      int(30)
      ["h"]=>
      int(23)
      ["i"]=>
      int(0)
      ["s"]=>
      int(0)
      ["f"]=>
      float(0)
      ["invert"]=>
      int(0)
      ["days"]=>
      int(0)
      ["from_string"]=>
      bool(false)
    }
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions