|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2016-04-11 16:27 UTC] mcloide1977 at gmail dot com
Description: ------------ When comparing 2 DateTime objects using comparison operators such as greater than, or less than, etc, you would expect that if DateTime object 1 has a timestamp that is greater than DateTime object 2 that it would return a truthful statement when being compared. While running some unit tests I managed to get some failures on a comparison test that simply did is $now >= $earlier. It, in all possible variations tested, failed where $now was never greater than or equals the $earlier DateTime object. That changed whenever there was a direct timestamp comparison happening or when the getTimeStamp method from the $now DateTime object. Before submitting this bug I have checked this bug report https://bugs.php.net/bug.php?id=68078 in which I had the hope that fixed the issue. It did not. The following test script was ran under: PHP 5.6.20-2+deb.sury.org~trusty+1 (cli) Copyright (c) 1997-2016 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies and under PHP 5.6.19 (cli) (built: Mar 14 2016 11:55:51) Copyright (c) 1997-2016 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies With the same end result. A copy of this test script can be found in: https://gist.github.com/mcloide/eb7db1cc38fe4c6476388902bda724c3 Test script: --------------- <?php foreach (['EST', 'EDT', 'CST', 'CDT', 'PST', 'PDT'] as $tz) { echo "---- TZ: $tz ---- \n"; $now = new DateTime('@' . (new DateTime('11:30 AM EST'))->getTimeStamp()); $earlier = new DateTime('7 AM', new DateTimeZone($tz)); echo $now->format('r') . "\n"; echo $earlier->format('r') . "\n"; $mod = $now->setTimeZone(new DateTimeZone($tz)); echo $now->format('r') . "\n"; echo $earlier->format('r') . "\n"; echo (int)($earlier < $now) . "\n"; echo $now->getTimestamp() . "\n"; echo (int)($earlier < $now) . "\n"; echo "------------------\n\n"; } Expected result: ---------------- When performing this comparison: echo (int)($earlier < $now) . "\n"; Regardless if getTimeStamp method is called the end result should be true. ---- TZ: CDT ---- Mon, 11 Apr 2016 16:30:00 +0000 Mon, 11 Apr 2016 07:00:00 -0600 Mon, 11 Apr 2016 10:30:00 -0600 Mon, 11 Apr 2016 07:00:00 -0600 1 1460392200 1 ------------------ Actual result: -------------- ---- TZ: CDT ---- Mon, 11 Apr 2016 16:30:00 +0000 Mon, 11 Apr 2016 07:00:00 -0600 Mon, 11 Apr 2016 10:30:00 -0600 Mon, 11 Apr 2016 07:00:00 -0600 0 1460392200 1 ------------------ PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Mon Nov 03 03:00:01 2025 UTC |
Interestingly enough, only happens with the shorter timezone names (PDT, PST) and not the longer ones (America/Los_Angeles): <?php $now = new \DateTime ('@1460394772'); $now -> setTimezone (new \DateTimeZone ('PDT')); printf ("(PDT) now->format('U'): %s\n", $now -> format ('U')); $now -> getTimestamp(); printf ("(PDT) now->format('U'): %s\n", $now -> format ('U')); echo "\n"; $now = new \DateTime ('@1460394772'); $now -> setTimezone (new \DateTimeZone ('America/Los_Angeles')); printf ("(America/Los_Angeles) now->format('U'): %s\n", $now -> format ('U')); $now -> getTimestamp(); printf ("(America/Los_Angeles) now->format('U'): %s\n", $now -> format ('U')); Expected -------------- (PDT) now->format('U'): 1460394772 (PDT) now->format('U'): 1460394772 (America/Los_Angeles) now->format('U'): 1460394772 (America/Los_Angeles) now->format('U'): 1460394772 Actual ------------- (PDT) now->format('U'): 1460365972 (PDT) now->format('U'): 1460394772 (America/Los_Angeles) now->format('U'): 1460394772 (America/Los_Angeles) now->format('U'): 1460394772 I am not actually sure which timestamp I would expect to see (1460365972 or 1460394772) - but I am 100% sure I would not expect to get a different value back after calling getTimestamp()Expanding on the point made by cmshelto at gmail dot com... The same exact (incorrect) behavior occurs when using offsets for the timezone: Test script: ------------ <?php $now = new \DateTime ('@1460394772'); $now -> setTimezone (new \DateTimeZone ('-0700')); printf ("(PDT) now->format('U'): %s\n", $now -> format ('U')); $now -> getTimestamp(); printf ("(PDT) now->format('U'): %s\n", $now -> format ('U')); echo "\n"; $now = new \DateTime ('@1460394772'); $now -> setTimezone (new \DateTimeZone ('America/Los_Angeles')); printf ("(America/Los_Angeles) now->format('U'): %s\n", $now -> format ('U')); $now -> getTimestamp(); printf ("(America/Los_Angeles) now->format('U'): %s\n", $now -> format ('U')); Expected -------------- (PDT) now->format('U'): 1460394772 (PDT) now->format('U'): 1460394772 (America/Los_Angeles) now->format('U'): 1460394772 (America/Los_Angeles) now->format('U'): 1460394772 Actual ------------- (PDT) now->format('U'): 1460365972 (PDT) now->format('U'): 1460394772 (America/Los_Angeles) now->format('U'): 1460394772 (America/Los_Angeles) now->format('U'): 1460394772 The two incorrect cases have a common code path in `timelib_unixtime2local()`. In the case of `America/Los_Angeles`, there is special logic to reset `tm->sse` to counter the fact that an earlier call to `timelib_unixtime2gmt()` modifies it. The other two cases (TZ-as-abbreviation, TZ-as-offset) do not do this. So far, this is the only place that I have been able to find which: 1) Manipulates `time->sse` 2) Follows the same code path for abbreviation and offset timezones 3) Follows a different path for timezone ids (e.g. `America/Los_Angeles`)