我在项目中使用DateTime(从UTC到欧洲/维也纳)转换所有日期。现在我的日期超过2038年,无法获得正确的时间。
示例代码:
$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
在2043-03-29和2043-10-25之间,由于“夏令时”,将从UTC计算+2小时。
如果我在2043-08-04 08:00:00更改为2037-08-04 08:00:00,我会得到正确的时间。
我知道这是2038整数32位的问题,但我如何使用整数64位和DateTime setTimezone函数?
由于
答案 0 :(得分:3)
如果问题与溢出的32位Unix时间戳有关,那么您将在1970年左右获得日期,并且类似的完全不正确的结果。但是,您的结果只有一小时。事实上,我们可以说小时是正确的,因为您只会得到错误的时区偏移量,因为您可以看到是否打印了时区信息:
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
这表明内部时间数据库缺少与当年一样的2043年信息。我们可以通过以下方式进一步证实:
$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')));
此代码(显然需要在32位平台上运行)打印:
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"
}
}
正如PHP所知,2043年是1月至12月的CET。
此信息来自Olson database:
有关世界时区的信息的协作汇编,主要用于计算机程序和操作系统
PHP手册包括instructions to update it,以防它已经缺少数据。如果它没有,你可能会运气不好。
答案 1 :(得分:1)
很明显DateTimeZone
转换限制在2037年。这就是为什么你在那年之前得到了正确的结果:
$met = new DateTimeZone('Europe/Vienna');
print_r($met->getTransitions());
最后的条目是:
[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
)