Bug #63442 [Ver->Nab]: DateTime::getTimestamp returns wrong value
| From: | cmb@php.net | Date: | Thu, 05 Nov 2020 12:56:52 +0000 |
| Subject: | Bug #63442 [Ver->Nab]: DateTime::getTimestamp returns wrong value | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-230125@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=63442&edit=1
ID: 63442
Updated by: cmb@php.net
Reported by: sea128 at post dot cz
Summary: DateTime::getTimestamp returns wrong value
-Status: Verified
+Status: Not a bug
Type: Bug
Package: Date/time related
Operating System: Windows 7 64 bit
PHP Version: 5.4.8
-Assigned To:
+Assigned To: derick
Block user comment: N
Private report: N
New Comment:
Let's analyze the OP's test script. When the first
::setTimestamp() is called, that results in 2012-10-28T02:00:00;
when the second ::setTimestamp() is called, that results in
2012-10-28T02:00:00. And this is correct; the first timestamp
correlates to 2012-10-28T02:00:00 CET, and the second timestamp
correlates to 2012-10-28T02:00:00 CEST. However, since CET/CEST
is not explicitly enforced, both times are 2012-10-28T02:00:00
Europe/Prague, and as such show the same timestamp.
In my humble opinion, the actual bug is the concept of DST.
I'm closing this as not a bug. Derick, please reopen if my
assessment is wrong.
Previous Comments:
------------------------------------------------------------------------
[2015-05-18 13:34:45] cmb@php.net
Related To: Bug #68204
------------------------------------------------------------------------
[2015-04-20 03:10:26] pasindu@php.net
http://3v4l.org/Crsc6
------------------------------------------------------------------------
[2015-02-17 14:24:53] howard at zedcore dot com
System: Debian Wheezy
PHP 5.4.36-0+deb7u3
------------------------------------------------------------------------
[2015-02-17 14:23:30] howard at zedcore dot com
Hello,
I have been able to reproduce this bug when setting DateTime objects to a date and time at the very
end of a daylight-savings-time transition.
Daylight-savings (at least in Britain) ends at 02:00:00.
The time goes from 2015-10-25T01:59:59+01:00 to 2015-10-25T01:00:00+00:00.
However, PHP's DateTime objects are broken for the one hour between 01:00:00+01:00 and
01:59:59+01:00. It reports time time offset as +0000 for these times.
I have written a PHPUnit test that reproduces this for both 2014 and 2015. I assume it is the same
for every transition.
This does not simply affect use of setTimestamp() and getTimestamp(), the timesone is wrong even
when constructing the DateTime object from an ISO-8601 string.
This is not an issue with the system's timezone data, as both BASH date and PHP's own
date() function work as expected (this is verified in 'test_ValidateData' below).
This is a fairly serious DateTime bug and I am shocked that it has not been addresses since 2012!
==========
<?php
/**
* The native PHP DateTime appears to have a bug relating to the end of British Summer Time.
*
* The transition is supposed to take place at 01:59:59+01:00 to leap immediately
* back to 01:00:00+00:00, however PHP's DateTime appears to actually revert to GMT at 01:00:00
*
* This relates to BOTH set/getTimestmap(), AND to setting the DateTime's value using setDate()
& setTime().
* Displaying the full ISO-8601 date-time in either of these cases shows the wrong time zone offset.
*
* setTimestamp() appears to assume that the timestamp you have given it is relative to the local
timezone
* during the end of Daylight Savings Time, and reduced the time by 1 hour.
*
* Calling getTimestamp() on DateTime objects at this edge case results in an offset timestamp, not
the
* expected epoch.
*
* Reported to PHP devs in 2012 (!)
*
* @see https://bugs.php.net/bug.php?id=63442
*
*/
class DateTime_DST_Test extends PHPUnit_Framework_TestCase
{
public function setUp()
{
date_default_timezone_set('Europe/London');
}
/**
* Check PHP's legacy date() function to validate the test data.
* @dataProvider DataProvider_DST_End
* @param $iEpoch
* @param $sISO8601
*/
public function test_ValidateData($iEpoch, $sISO8601)
{
$this->assertEquals($sISO8601, date('c', $iEpoch), 'date()');
}
/**
* Bug is present when setTimestamp() is used.
* @dataProvider DataProvider_DST_End
* @param integer $iEpoch
* @param string $sISO8601
*/
public function test_WrongTimezone_setTimestamp($iEpoch, $sISO8601)
{
$dtPHP = new DateTime();
$dtPHP->setTimestamp($iEpoch);
$this->assertEquals($iEpoch, $dtPHP->getTimestamp());
$this->assertEquals($sISO8601, $dtPHP->format('c'));
}
/**
* Bug is present even when constructed without using setTimestamp().
* @dataProvider DataProvider_DST_End
* @param integer $iEpoch
* @param string $sISO8601
*/
public function test_WrongTimezone_SetFromISO($iEpoch, $sISO8601)
{
$dtPHP = new DateTime($sISO8601, new DateTimeZone('UTC'));
$this->assertEquals($iEpoch, $dtPHP->getTimestamp());
$dtPHP->setTimezone(new DateTimeZone('Europe/London'));
$this->assertEquals($iEpoch, $dtPHP->getTimestamp());
$this->assertEquals($sISO8601, $dtPHP->format('c'));
}
/**
* Bug is present even when the object is converted to UTC.
* @dataProvider DataProvider_DST_End
* @param integer $iEpoch
*/
public function test_WrongTimezone_SetToUTC($iEpoch)
{
$dtPHP = new DateTime();
$dtPHP->setTimestamp($iEpoch);
$dtPHP->setTimezone(new DateTimeZone('UTC'));
$this->assertEquals($iEpoch, $dtPHP->getTimestamp());
}
/**
* Bug is NOT present if DateTime is in UTC when setTimestamp() is called.
* @dataProvider DataProvider_DST_End
* @param integer $iEpoch
*/
public function test_CorrectTimezone_StartInUTC($iEpoch)
{
date_default_timezone_set('UTC');
$dtPHP = new DateTime();
$dtPHP->setTimezone(new DateTimeZone('UTC'));
$dtPHP->setTimestamp($iEpoch);
$this->assertEquals($iEpoch, $dtPHP->getTimestamp());
}
/**
* Bug is present if getTimestamp() is called after converting back out out of UTC
* @dataProvider DataProvider_DST_End
* @param integer $iEpoch
* @param string $sISO8601
*/
public function test_WrongTimezone_StartInUTC_ChangeTimezone($iEpoch, $sISO8601)
{
date_default_timezone_set('UTC');
$dtPHP = new DateTime();
$dtPHP->setTimezone(new DateTimeZone('UTC'));
$dtPHP->setTimestamp($iEpoch);
$dtPHP->setTimezone(new DateTimeZone('Europe/London'));
$this->assertEquals($iEpoch, $dtPHP->getTimestamp());
$this->assertEquals($sISO8601, $dtPHP->format('c'));
}
/**
* Epochs right at the end of Daylight savings in Europe/London.
* ISO-8601 date-times are in the Europe/London timezone.
*
* @see test_DateTime_DST_End
* @return array [$iEpoch, $sISO8601]
*/
public static function DataProvider_DST_End()
{
return array(
array(1414281599, '2014-10-26T00:59:59+01:00'), // Passes
array(1414281600, '2014-10-26T01:00:00+01:00'), // Fails
array(1414285199, '2014-10-26T01:59:59+01:00'), // Fails
array(1414285200, '2014-10-26T01:00:00+00:00'), // Passes
array(1445731199, '2015-10-25T00:59:59+01:00'), // Passes
array(1445731200, '2015-10-25T01:00:00+01:00'), // Fails
array(1445734799, '2015-10-25T01:59:59+01:00'), // Fails
array(1445734800, '2015-10-25T01:00:00+00:00'), // Passes
);
}
}
------------------------------------------------------------------------
[2014-09-04 18:47:27] mj1856 at hotmail dot com
There's some other strangeness here also. Consider:
$tz = new DateTimeZone('Europe/Paris');
$dt = new DateTime('2014-10-26T02:30', $tz);
echo $dt->format(DateTime::ISO8601) . " (" . $dt->getTimeStamp() . ")\n";
$ts = $dt->getTimeStamp() - 3600;
$dt = new DateTime("@$ts", new DateTimeZone('UTC'));
$dt->setTimeZone($tz);
echo $dt->format(DateTime::ISO8601) . " (" . $dt->getTimeStamp() . ")\n";
OUTPUT:
2014-10-26T02:30:00+0100 (1414287000)
2014-10-26T02:30:00+0200 (1414287000)
So even though going through UTC fixed the offset shown in the formatting, it still adjusted the
timestamp. The second value should have the timestamp 141283400.
This is a really dangerous bug that has been sitting for too long. Please raise priority. Thanks.
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=63442
--
Edit this bug report at https://bugs.php.net/bug.php?id=63442&edit=1