PHP DateTime setTimezone 2038
Asked Answered
S

2

2

I convert all dates with DateTime (from UTC to Europe/Vienna) in my project. Now I have dates with above 2038, and cannot get the correct time.

Example Code:

$met = new DateTimeZone('Europe/Vienna');
$utc = new DateTimeZone('UTC');

$date = new DateTime('2043-08-04 08:00:00', $utc);
$date->setTimezone($met);
echo $date->format('Y-m-d H:i:s'); // Output is: 2043-08-04 09:00:00 instead of 2043-08-04 10:00:00

Between 2043-03-29 and 2043-10-25 there is to calculate +2 hours from UTC, because of "summertime".

If I change 2043-08-04 08:00:00 to 2037-08-04 08:00:00 I get the correct time.

I know it is a 2038 problem with integer 32 bit, but how I can use integer 64 bit with DateTime setTimezone function?

Thanks

Supertax answered 21/3, 2017 at 15:50 Comment(3)
The DateTime class is not affected by 2038 issue, even on 32-bit PHP.Balch
... except when it is (see answers so far). Oh my... :)Balch
Since time zone and daylight savings laws change, they can't be relied upon to be the same that far into the future anyway.Ekg
I
3

If the issue had anything to do with overflowing 32-bit Unix timestamps you'd be getting dates around 1970 and similar totally incorrect results. However, your result is only off by one hour. In fact, we could argue that the hour is correct since you're only getting a wrong time zone offset, as you can see if you print time zone information:

var_dump($date);
echo $date->format('c');
object(DateTime)#3 (3) {
  ["date"]=>
  string(26) "2043-08-04 09:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(13) "Europe/Vienna"
}
2043-08-04T09:00:00+01:00

This suggests that the internal time database is missing information for year 2043 as it has for current year. We can further confirm this with:

$met = new DateTimeZone('Europe/Vienna');
var_dump($met->getTransitions((new DateTime('2017-01-01'))->format('U'), (new DateTime('2017-12-31'))->format('U')));
var_dump($met->getTransitions((new DateTime('2043-01-01'))->format('U'), (new DateTime('2043-12-31'))->format('U')));

This code (that apparently needs to run on a 32-bit platforms) prints:

array(3) {
  [0]=>
  array(5) {
    ["ts"]=>
    int(1483225200)
    ["time"]=>
    string(24) "2016-12-31T23:00:00+0000"
    ["offset"]=>
    int(3600)
    ["isdst"]=>
    bool(false)
    ["abbr"]=>
    string(3) "CET"
  }
  [1]=>
  array(5) {
    ["ts"]=>
    int(1490490000)
    ["time"]=>
    string(24) "2017-03-26T01:00:00+0000"
    ["offset"]=>
    int(7200)
    ["isdst"]=>
    bool(true)
    ["abbr"]=>
    string(4) "CEST"
  }
  [2]=>
  array(5) {
    ["ts"]=>
    int(1509238800)
    ["time"]=>
    string(24) "2017-10-29T01:00:00+0000"
    ["offset"]=>
    int(3600)
    ["isdst"]=>
    bool(false)
    ["abbr"]=>
    string(3) "CET"
  }
}
array(1) {
  [0]=>
  array(5) {
    ["ts"]=>
    int(2303679600)
    ["time"]=>
    string(24) "2042-12-31T23:00:00+0000"
    ["offset"]=>
    int(3600)
    ["isdst"]=>
    bool(false)
    ["abbr"]=>
    string(3) "CET"
  }
}

As PHP is aware of it, year 2043 is CET from January to December.

This information comes from the Olson database:

a collaborative compilation of information about the world's time zones, primarily intended for use with computer programs and operating systems

The PHP manual includes instructions to update it, in case it already has the missing data. If it doesn't, you're probably out of luck.

Increscent answered 21/3, 2017 at 16:22 Comment(0)
C
1

Aparrently the DateTimeZone transitions are limited to 2037. That's why you are getting the right results until that year:

$met = new DateTimeZone('Europe/Vienna');

print_r($met->getTransitions());

The last entries are:

[139] => Array
    (
        [ts] => 2108595600
        [time] => 2036-10-26T01:00:00+0000
        [offset] => 3600
        [isdst] => 
        [abbr] => CET
    )

[140] => Array
    (
        [ts] => 2121901200
        [time] => 2037-03-29T01:00:00+0000
        [offset] => 7200
        [isdst] => 1
        [abbr] => CEST
    )

[141] => Array
    (
        [ts] => 2140045200
        [time] => 2037-10-25T01:00:00+0000
        [offset] => 3600
        [isdst] => 
        [abbr] => CET
    )
Crossstaff answered 21/3, 2017 at 16:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.