我在PHP中遇到了一件奇怪的事情。在时区Europe/Oslo
中,我从时间戳2020-03-29 03:00:00
中减去了一个小时(这恰好是Dailight Savings Time偏移发生的时间),并且得到了完全相同的时间戳2020-03-29 03:00:00
!它应该导致2020-03-29 01:00:00
。怎么没有呢?
一直到2020-03-29 03:59:59
,当减去一小时时,它会返回完全相同的时间戳(尝试sub()
和modify()
都使用)。此后的下一秒正确显示为2020-03-29 03:00:00
。
您可以这样复制它:
date_default_timezone_set('Europe/Oslo');
echo (new \DateTime('2020-03-29 03:00:00'))->sub(new \DateInterval('PT1H'))->format('Y-m-d H:i:s');
我已经在PHP 7.1.33、7.3.10和7.3.18中对此进行了测试。
PS。向2020-03-29 01:00:00
添加1小时确实可以正确获得2020-03-29 03:00:00
。
虽然我同意这是不好的/笨拙的行为,但您可以通过严格只在UTC中存储或计算日期来避免这种情况。考虑时区严格仅用于显示目的,这样可以避免lot令人头疼。
例如:
// input
$utc = new DateTimeZone('UTC');
$user_tz = new DateTimeZone('Europe/Oslo');
$input = new DateTime('2020-03-29 03:00:00', $user_tz);
$storage = (clone $input)->setTimezone($utc);
var_dump(
$input->format('c'),
$storage->format('c')
);
// compute
$interval = new DateInterval('PT1H');
$storage->sub($interval);
var_dump(
$storage->format('c')
);
// display
$display = (clone $storage)->setTimezone($user_tz);
var_dump(
$display->format('c')
);
输出:
string(25) "2020-03-29T03:00:00+02:00"
string(25) "2020-03-29T01:00:00+00:00"
string(25) "2020-03-29T00:00:00+00:00"
string(25) "2020-03-29T01:00:00+01:00"