考虑我们想要添加或减去一秒的代码:
date_default_timezone_set("Europe/Amsterdam");
$time = 1477789199;
echo $time . ' - ' . date('r', $time) . "\n";
// 1477789199 - Sun, 30 Oct 2016 02:59:59 +0200
这是正确的,因为此时间戳仍在DST(夏令时/夏令时)内。
但现在让我们在时间戳整数上添加一秒,然后退出 DST:
$new = $time + 1;
echo $new . ' - ' . date('r', $new);
// 1477789200 - Sun, 30 Oct 2016 02:00:00 +0100
万岁! PHP看到一秒后不再有DST,并显示一个合适的时间字符串。
但是,如果我们没有在时间戳整数中添加第二个,但是我们使用strtotime()
添加了一秒,那该怎么办呢?
$new = strtotime('+1 second', $time);
echo $new . ' - ' . date('r', $new);
// 1477792800 - Sun, 30 Oct 2016 03:00:00 +0100
糟糕!我们只用了一个多小时而不是一秒钟。如果你加一秒,一小时,一天或一年,你总会得到一个额外的小时。即使你增加了多年,你也只会多花一个小时,这很奇怪,因为我们每年都会进入和退出DST,但无论你添加了多少年,你只需要多一个小时
但是,一旦我们在10月退出 DST并减去一秒钟,一切都会好起来......
但话又说回来。如果我们在三月份,我们刚刚进入夏令时,我们减去一秒钟,我们反过来观察完全一样。
等等,什么?!那么......?
echo strtotime('+ 1 second - 1 second', 1477789199); // echoes 1477792799
哇...
对我来说,这听起来像个臭虫。或者这是'按设计'?有人甚至知道这是否记录在某处,或者是否需要报告?答案 0 :(得分:1)
行为是“记录良好”......在测试中:
请参阅https://bugs.php.net/bug.php?id=30532(也按预期显示您的预期结果)和相关的测试文件(断言当前行为是正确的)https://github.com/php/php-src/blob/master/ext/date/tests/bug30532.phpt
<?php date_default_timezone_set("America/New_York");
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 EDT +1 hour'))."\n";
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 EDT +2 hours'))."\n";
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 EDT +3 hours'))."\n";
/* 2004-10-31 01:00:00 EDT
2004-10-31 01:00:00 EST
2004-10-31 02:00:00 EST */
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 +1 hour'))."\n";
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 +2 hours'))."\n";
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 +3 hours'))."\n";
/* 2004-10-31 01:00:00 EDT
2004-10-31 02:00:00 EST
2004-10-31 03:00:00 EST */
请注意,在前一种情况下,时区(此处为:EDT
)直接传递给字符串,后者则不是。
通常strtotime
正在取时间戳(即2004-10-31
- 或在您的特定情况下:传递的时间戳),转换为具有单个参数的表示,忽略DST(即个别小时,分钟) ,秒,日,月,年等),操作应用于它,然后转换回时间戳。
特别是:
echo date('r', strtotime('+ 0 second', 1477789199));
#> Sun, 30 Oct 2016 02:59:59 +0100
strtotime()
在转换之后抛出时区,即只接受
Sun, 30 Oct 2016 02:59:59
然后将主要适用的时区应用到您的时区位置(即Europe/Amsterdam
),最后得到CET
(主要!) - CEST
也是可能的,但只是第二选择。
现在,回顾上面的测试,只需明确指定原始时区。
因此,如果您希望它以您需要的方式行事:
echo date('r', strtotime('CEST', 1477789199));
#> Sun, 30 Oct 2016 02:59:59 +0200
echo date('r', strtotime('CEST + 1 second', 1477789199));
#> Sun, 30 Oct 2016 02:00:00 +0100
事实上,预先'CEST '
一直处于正常状态(因为如果CET
不匹配且CEST
上没有重叠,它将始终回退到CET
- &gt; CEST
过渡)。