php - strtotime() 有错误吗?

标签 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

哎呀!我们只是提前了一个多小时而不是一秒钟。如果你增加一秒钟、一小时、一天或一年,你总是会多一个小时,这并不重要。即使您添加多个年份,您也只会多获得一个小时,这很奇怪,因为我们每年都会进入和退出夏令时,但无论您添加多少年,您都只会多获得一个小时

但是一旦我们在 10 月退出 DST 并减去一秒,一切都会好起来...

不过话又说回来了。如果我们在三月,刚进入夏令时,我们减去一秒,我们观察到完全相同的反向。


等等,什么?!那么……?

echo strtotime('+ 1 second - 1 second', 1477789199); // echoes 1477792799

哇...


对我来说,这听起来像是一个错误。或者这是“设计使然”?有谁知道这是否记录在某处,或者是否需要报告?

最佳答案

该行为“有据可查”......在测试中:

参见 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 结尾code> 也是可以的,但只是第二选择。

现在,回顾上面的测试,只需明确指定原始时区即可。

因此,如果您希望它按您需要的方式运行:

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 ' 之前添加任何时候都没有问题(因为如果 CEST 不是,它将始终回退到 CET匹配并且 CET -> CEST 转换没有重叠)。

关于php - strtotime() 有错误吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39622216/

相关文章:

php - 从 foreach php 中删除重复项

java - 如何将时间戳附加到 rdd 并推送到 elasticsearch

java - 按时间升序对 Hashmap 数组进行排序

postgresql - 如何检查某个事件时间是否在 PostgreSQL 的时间范围内?

php - strtotime php mysql

php - 使用旧/新语法调用 PHP 父构造函数

php - 在 Ubuntu 上安装 CakePHP 2 控制台

php - 从自定义自定义日期显示日历

php - PHP 中的工作日(周一至周五)

PHP strtotime 上周的每一天