strtotime()有错误吗?

时间:2016-09-21 16:46:40

标签: php time strtotime

考虑我们想要添加或减去一秒的代码:

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

哇...

对我来说,这听起来像个臭虫。或者这是'按设计'?有人甚至知道这是否记录在某处,或者是否需要报告?

1 个答案:

答案 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过渡)。