PHP DateTime setTimezone 2038

丶灬走出姿态 提交于 2019-12-06 09:34:49

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.

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
    )
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!