php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #68549 Timezones and offsets are not properly used when working with dates
Submitted: 2014-12-05 05:22 UTC Modified: 2021-11-09 09:26 UTC
Votes:9
Avg. Score:4.9 ± 0.3
Reproduced:9 of 9 (100.0%)
Same Version:3 (33.3%)
Same OS:4 (44.4%)
From: mfaust at usinternet dot com Assigned:
Status: Closed Package: Date/time related
PHP Version: 5.6.3 OS: Linux
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: mfaust at usinternet dot com
New email:
PHP Version: OS:

 

 [2014-12-05 05:22 UTC] mfaust at usinternet dot com
Description:
------------
Unix timestamps are not respected during daylight savings transitions. When specifying a timestamp during a repeated hour, DateTime silently(incorrectly) modifies the timestamp to the previous hour.

In regards to the proposed https://wiki.php.net/rfc/datetime_and_daylight_saving_time change, there are some current behaviors in regards to the "fall back" repeated hour that sorely need to be addressed. For those that understand and need proper and accurate date/time handling it is crucial that these inconsistent behaviors are eliminated.


Test script:
---------------
//A timestamp indicates a fixed point in time, irregardless of timezone and daylight savings, so PHP must not change it when setting it:
$x = new DateTime();
$x->setTimezone(new DateTimezone('America/Chicago'));
$x->setTimestamp(1446357600);
echo $x->format('c') . "\n";

$x->setTimestamp(1446361200);
echo $x->format('c') . "\n"; //This should have a different offset since it's outside DST
echo $x->getTimestamp();

//Simpler example
$x = new DateTime();
$x->setTimezone(new DateTimezone('America/Chicago'));
$x->setTimestamp(1446361200);
echo $x->getTimestamp(); //Returns a different timestamp. No apparent way to specify a timestamp during the repeated hour.


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-12-05 05:33 UTC] yohgaki@php.net
http://3v4l.org/HGGjd

HHVM seems working correctly.
 [2015-03-06 16:06 UTC] bestcoder at ymail dot com
This is another test case showing that daylight saving time is poorly handled.

<?php
echo "Expected DateTime in ISO8601: 2014-10-26T02:00:00+0200
Expected DateTime in RFC850: Sunday, 26-Oct-14 02:00:00 GMT+0200
Expected Timestamp: 1414281600\n";
echo "--------------------------------------------\n";

$date = new \DateTime("2014-10-26T02:00:00+02:00");
$date->setTimeZone(new \DateTimeZone('Europe/Paris'));

echo "Actual DateTime in ISO8601: ", $date->format(\DateTime::ISO8601) ,"\n";
echo "Actual DateTime in RFC850: ", $date->format(\DateTime::RFC850) ,"\n";
echo "Actual timestamp: ", $date->getTimestamp() ,"\n";


echo "--------------------------------------------\n";
echo "--------------------------------------------\n";



echo "Expected DateTime in ISO8601: 2014-10-26T03:00:00+0200
Expected DateTime in RFC850: Sunday, 26-Oct-14 03:00:00 GMT+0200
Expected timestamp: 1414285200\n";
echo "--------------------------------------------\n";

$date = new \DateTime("2014-10-26T03:00:00+02:00");
$date->setTimeZone(new \DateTimeZone('Europe/Paris'));

echo "Actual DateTime in ISO8601: ", $date->format(\DateTime::ISO8601) ,"\n";
echo "Actual DateTime in RFC850: ", $date->format(\DateTime::RFC850) ,"\n";
echo "Actual timestamp: ", $date->getTimestamp() ,"\n";
?>

This scripts run on PHP 5.5.9 output :

Expected DateTime in ISO8601: 2014-10-26T02:00:00+0200
Expected DateTime in RFC850: Sunday, 26-Oct-14 02:00:00 GMT+0200
Expected Timestamp: 1414281600
--------------------------------------------
Actual DateTime in ISO8601: 2014-10-26T02:00:00+0200
Actual DateTime in RFC850: Sunday, 26-Oct-14 02:00:00 CEST
Actual timestamp: 1414285200
--------------------------------------------
--------------------------------------------
Expected DateTime in ISO8601: 2014-10-26T03:00:00+0200
Expected DateTime in RFC850: Sunday, 26-Oct-14 03:00:00 GMT+0200
Expected timestamp: 1414285200
--------------------------------------------
Actual DateTime in ISO8601: 2014-10-26T02:00:00+0100
Actual DateTime in RFC850: Sunday, 26-Oct-14 02:00:00 CET
Actual timestamp: 1414285200


So according to PHP 'Sunday, 26-Oct-14 02:00:00 CEST' and 'Sunday, 26-Oct-14 02:00:00 CET' refer to same timestamp '1414285200'  which is wrong. For 'Sunday, 26-Oct-14 02:00:00 CEST', it should show 1414281600.
 [2015-12-30 22:07 UTC] mj1856 at hotmail dot com
As seen here:  http://stackoverflow.com/q/34533604/634824

$date = new \DateTime("now", new \DateTimeZone("UTC"));
$date->setTimestamp(1540686600);
echo $date->getTimestamp() . "\n";  //1540686600
echo $date->format('c') . "\n";     //2018-10-28T00:30:00+00:00

This is wrong, as the timestamp corresponds to 1:30:00+01:00

Additionally,
$date->setTimezone(new \DateTimeZone("Europe/London"));
echo $date->getTimestamp() . "\n";  //1540690200

This is really bad, as changing the timezone should NEVER change the timestamp.
 [2021-11-08 11:04 UTC] roel dot harbers at on2it dot net
Still going wrong in php 7.4.3:

<?php

// $originalTimestamp = 1636275599; // ok
$originalTimestamp = 1636275600; // wrong (- 3600 sec)
// $originalTimestamp = 1636279199; // wrong (- 3600 sec)
// $originalTimestamp = 1636279200; // ok
$tz = new DateTimeZone('America/Los_Angeles');

// this fails in the opposite way:
// $originalTimestamp = 1635638399; // ok
// $originalTimestamp = 1635638400; // wrong (+ 3600 sec)
// $originalTimestamp = 1635641999; // wrong (+ 3600 sec)
// $originalTimestamp = 1635642000; // ok
// $tz = new DateTimeZone('Europe/Amsterdam');

$dt = new DateTime('now', $tz);
print_r($dt);
printf("now ISO8601 format: %s\n", $dt->format(DateTimeInterface::ISO8601));
printf("now timestamp: %d\n", $dt->getTimestamp());

printf("\nsetting timestamp to %d:\n\n", $originalTimestamp);
$dt->setTimestamp($originalTimestamp);

$actualTimestamp = $dt->getTimestamp();
print_r($dt);
printf("DateTime object's ISO8601 format: %s\n", $dt->format(DateTimeInterface::ISO8601));
printf("DateTime object's UNIX timestamp: %d\n", $actualTimestamp);

printf("difference (should be 0): %d\n", $actualTimestamp - $originalTimestamp);
?>

How is this bug seven years old with not even a response in sight...
 [2021-11-08 11:28 UTC] heiglandreas@php.net
@ roel dot harbers at on2it dot net

There is a response in sight, which is the - already in the initial bugreport mentionend - RFC (https://wiki.php.net/rfc/datetime_and_daylight_saving_time)

The RFC has been accepted but so far not been implemented.

As PHP is an OpenSource Project: Feel free to create the appropriate PullRequest to fix this issue.
 [2021-11-09 07:33 UTC] roel dot harbers at on2it dot net
Thanks for the reply :)

I'm looking at fixing it, and it seems there might already be test cases for it?

EXPECTED FAILED TEST SUMMARY
---------------------------------------------------------------------
DateTime::add() -- fall type2 type3 [ext/date/tests/DateTime_add-fall-type2-type3.phpt]  XFAIL REASON: Various bugs exist
DateTime::add() -- fall type3 type2 [ext/date/tests/DateTime_add-fall-type3-type2.phpt]  XFAIL REASON: Various bugs exist
DateTime::add() -- fall type3 type3 [ext/date/tests/DateTime_add-fall-type3-type3.phpt]  XFAIL REASON: Various bugs exist
DateTime::add() -- spring type2 type3 [ext/date/tests/DateTime_add-spring-type2-type3.phpt]  XFAIL REASON: Various bugs exist
DateTime::add() -- spring type3 type2 [ext/date/tests/DateTime_add-spring-type3-type2.phpt]  XFAIL REASON: Various bugs exist
DateTime::add() -- spring type3 type3 [ext/date/tests/DateTime_add-spring-type3-type3.phpt]  XFAIL REASON: Various bugs exist
DateTime::diff() -- fall type2 type3 [ext/date/tests/DateTime_diff-fall-type2-type3.phpt]  XFAIL REASON: Various bugs exist
DateTime::diff() -- fall type3 type2 [ext/date/tests/DateTime_diff-fall-type3-type2.phpt]  XFAIL REASON: Various bugs exist
DateTime::diff() -- fall type3 type3 [ext/date/tests/DateTime_diff-fall-type3-type3.phpt]  XFAIL REASON: Various bugs exist
DateTime::diff() -- spring type2 type3 [ext/date/tests/DateTime_diff-spring-type2-type3.phpt]  XFAIL REASON: Various bugs exist
DateTime::diff() -- spring type3 type2 [ext/date/tests/DateTime_diff-spring-type3-type2.phpt]  XFAIL REASON: Various bugs exist
DateTime::diff() -- spring type3 type3 [ext/date/tests/DateTime_diff-spring-type3-type3.phpt]  XFAIL REASON: Various bugs exist
DateTime::sub() -- fall type2 type3 [ext/date/tests/DateTime_sub-fall-type2-type3.phpt]  XFAIL REASON: Various bugs exist
DateTime::sub() -- fall type3 type2 [ext/date/tests/DateTime_sub-fall-type3-type2.phpt]  XFAIL REASON: Various bugs exist
DateTime::sub() -- fall type3 type3 [ext/date/tests/DateTime_sub-fall-type3-type3.phpt]  XFAIL REASON: Various bugs exist
DateTime::sub() -- spring type2 type3 [ext/date/tests/DateTime_sub-spring-type2-type3.phpt]  XFAIL REASON: Various bugs exist
DateTime::sub() -- spring type3 type2 [ext/date/tests/DateTime_sub-spring-type3-type2.phpt]  XFAIL REASON: Various bugs exist
DateTime::sub() -- spring type3 type3 [ext/date/tests/DateTime_sub-spring-type3-type3.phpt]  XFAIL REASON: Various bugs exist
Bug #52480 (Incorrect difference using DateInterval) [ext/date/tests/bug52480.phpt]  XFAIL REASON: See https://bugs.php.net/bug.php?id=52480
RFC: DateTime and Daylight Saving Time Transitions (zone type 3, bd2) [ext/date/tests/rfc-datetime_and_daylight_saving_time-type3-bd2.phpt]  XFAIL REASON: Still not quite right
RFC: DateTime and Daylight Saving Time Transitions (zone type 3, fs) [ext/date/tests/rfc-datetime_and_daylight_saving_time-type3-fs.phpt]  XFAIL REASON: Still not quite right
=====================================================================

(on branch PHP-7.4)
 [2021-11-09 09:26 UTC] heiglandreas@php.net
It might indeed be the case that there are testcases already available.
 [2021-11-09 13:25 UTC] roel dot harbers at on2it dot net
I have added some unittests to clearly show the issue in https://github.com/php/php-src/pull/7636

It appears that PHP 8.1 *does* work correctly when using `setTimezone` (but not for `setTimestamp`), while in PHP 7.4 neither works.

I tried to figure out how to fix it, and I've tracked it down to this: https://github.com/php/php-src/blob/2b1b384d9a58aea734933ebcbc9ec2f1aa14b946/ext/date/lib/tm2unixtime.c

It appears that this returns the *previous* timezone info. I'm struggling to fix it tho, with how complex the code is.
 [2021-11-09 13:28 UTC] roel dot harbers at on2it dot net
sorry, the link misses the line number: https://github.com/php/php-src/blob/2b1b384d9a58aea734933ebcbc9ec2f1aa14b946/ext/date/lib/tm2unixtime.c#L391
 [2021-11-10 10:36 UTC] roel dot harbers at on2it dot net
I created a PR with a fix (for PHP7.4): https://github.com/php/php-src/pull/7639
 [2022-05-20 12:25 UTC] git@php.net
Automatic comment on behalf of derickr
Revision: https://github.com/php/php-src/commit/20d8c1bea584aef6ec83417bea3a637d1e657ee6
Log: Fixed bug #68549 (Timezones and offsets are not properly used when working with dates)
 [2022-05-20 12:25 UTC] git@php.net
-Status: Open +Status: Closed
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Mar 19 10:01:30 2024 UTC