Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
jabelli opened this issue Jun 8, 2022 · 5 comments
Closed

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

jabelli opened this issue Jun 8, 2022 · 5 comments

Comments

@jabelli
Copy link

jabelli commented Jun 8, 2022

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

@hormus
Copy link

hormus commented Jun 12, 2022

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

?>

@derickr
Copy link
Member

derickr commented Jun 17, 2022

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

@ToshY
Copy link

ToshY commented Jul 20, 2022

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

@derickr
Copy link
Member

derickr commented Jul 21, 2022

Just now :-)

@jabelli
Copy link
Author

jabelli commented Jul 21, 2022

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
Projects
None yet
Development

No branches or pull requests

5 participants