filemtime 可以在夏令时变化时与 strtotime 进行比较吗?
Can filemtime be compared with strtotime at the daylight savings change?
我有一些 PHP 代码可以在源数据文件过期时发送警告并自动关闭服务。这是使用以下比较完成的:
警告:
filemtime($file_location) < strtotime('-15 minute')
考虑停止服务:
filemtime($file_location) < strtotime('-1 hour')
从 3:00 AM CDT 夏令时开始的 1 小时开始,这会错误地将文件报告为超过 15 分钟。在该小时快结束时,它还错误地报告该文件存在时间超过 1 小时。 4:00 上午 CDT 事情 return 正常。
关于 filemtime() 或 strtotime() 函数,有什么我不知道的东西可以解释这种行为吗?据我了解,return UNIX 时间戳和时间戳都是 UTC 定义的,所以我不确定是什么导致了这个问题。
根据目前的答案,我 运行 在我们的服务器上进行了此测试:
`
for($i = 1; $i <=4; $i++){
// let's say current time is this:
date_default_timezone_set('America/Winnipeg');
$current_timestamp = strtotime('2016-03-13 0'.$i.':00:00'); // 1457856060
// DST start at 03:00 that day, so 60 minutes before the time should be 01:01
$ts = $current_timestamp - 1*60*60;
echo '-3600s: ', $ts, ", ", date('Y-m-d H:i:s', $ts), "\n";
// 1457852460, 2016-10-30 02:59:00, correct
// now let's test strtotime with -1 hour
$ts = strtotime('-1 hour', $current_timestamp);
echo '-1 hour: ', $ts, ", ", date('Y-m-d H:i:s', $ts), "\n";
// 1457856060, 2016-10-30 03:01:00, completely wrong
// DateTime implementation seems smarter:
$dt = new DateTime();
$dt->setTimestamp($current_timestamp);
$dt->sub(new DateInterval('PT1H'));
echo 'sub PT1H: ', $dt->getTimestamp(), ", ", $dt->format('Y-m-d H:i:s'), "\n";
// 1457856060, 2016-10-30 03:01:00, correct
echo "\n\n";
echo 'TS ', $current_timestamp, ", ", date('Y-m-d H:i:s', $current_timestamp), "\n";
echo "\n\n";
}
`
-3600s: 1457848800, 2016-03-13 00:00:00
-1小时:1457848800,2016-03-1300:00:00
sub PT1H: 1457848800, 2016-03-13 00:00:00
TS 1457852400, 2016-03-13 01:00:00
-3600s: 1457852400, 2016-03-13 01:00:00
-1 小时: 1457856000, 2016-03-13 03:00:00
sub PT1H: 1457856000, 2016-03-13 03:00:00
TS 1457856000, 2016-03-13 03:00:00
-3600s: 1457852400, 2016-03-13 01:00:00
-1 小时: 1457856000, 2016-03-13 03:00:00
sub PT1H: 1457856000, 2016-03-13 03:00:00
TS 1457856000, 2016-03-13 03:00:00
-3600s: 1457856000, 2016-03-13 03:00:00
-1 小时: 1457856000, 2016-03-13 03:00:00
sub PT1H: 1457856000, 2016-03-13 03:00:00
TS 1457859600, 2016-03-13 04:00:00
这令人深感困惑。在我的时区,夏令时从 3 月 27 日开始,以下所有表达式 return 相同的 UNIX 时间戳:
var_dump(strtotime("27 March 2016 02:00"));
var_dump(strtotime("- 60 minute", strtotime("27 March 2016 02:00")));
var_dump(strtotime("- 1 hour", strtotime("27 March 2016 02:00")));
var_dump(strtotime("27 March 2016 02:00 - 1 hour"));
var_dump((new DateTime("27 March 2016 02:00"))->format("U"));
var_dump((new DateTime("27 March 2016 02:00"))->sub(new DateInterval("PT1H"))->format("U"));
如果我仔细考虑一下,我可能会相信这是预期的行为。 01:00 3 月 27 日 此处不存在。但这肯定不直观。
更令人困惑的是,从02:00中减去15分钟给出了未来的答案,即02:45。如果你足够眯眼,即使第一个结果有点意义,这个结果也一定是一个错误。
关于这个有an open bug report近4年没有动过。
这给您留下了两个选择。您可以在代码中添加一个 if
子句,如果最初的减法没有减少时间戳,则减去 2 小时或 75 分钟。或者您可以简单地从当前时间戳中减去 3600 或 900 秒,而不是使用 strtotime
。两者都不是特别优雅,但我们就是这样。
似乎 strtotime
不够聪明,无法在对相对值进行操作时考虑 DST 更改:
// let's say current time is this:
date_default_timezone_set('Europe/Berlin');
$current_timestamp = strtotime('2016-10-30 01:59:00'); // 1477785540
// DST ends at 03:00 that day, so 120 minutes later the time should be 02:59
$ts = $current_timestamp + 2*60*60;
echo $ts, ", ", date('Y-m-d H:i:s', $ts), "\n";
// 1477792740, 2016-10-30 02:59:00, correct
// now let's test strtotime with +2 hours
$ts = strtotime('+2 hours', $current_timestamp);
echo $ts, ", ", date('Y-m-d H:i:s', $ts), "\n";
// 1477796340, 2016-10-30 03:59:00, completely wrong
// DateTime implementation seems smarter:
$dt = new DateTime();
$dt->setTimestamp($current_timestamp);
$dt->add(new DateInterval('PT2H'));
echo $dt->getTimestamp(), ", ", $dt->format('Y-m-d H:i:s');
// 1477792740, 2016-10-30 02:59:00, correct
在您的特定情况下,我只是直接比较时间戳(差异显然以秒为单位),但是使用 DateTime
和 TimeInterval
也是一种选择。
我有一些 PHP 代码可以在源数据文件过期时发送警告并自动关闭服务。这是使用以下比较完成的:
警告:
filemtime($file_location) < strtotime('-15 minute')
考虑停止服务:
filemtime($file_location) < strtotime('-1 hour')
从 3:00 AM CDT 夏令时开始的 1 小时开始,这会错误地将文件报告为超过 15 分钟。在该小时快结束时,它还错误地报告该文件存在时间超过 1 小时。 4:00 上午 CDT 事情 return 正常。
关于 filemtime() 或 strtotime() 函数,有什么我不知道的东西可以解释这种行为吗?据我了解,return UNIX 时间戳和时间戳都是 UTC 定义的,所以我不确定是什么导致了这个问题。
根据目前的答案,我 运行 在我们的服务器上进行了此测试:
`
for($i = 1; $i <=4; $i++){
// let's say current time is this:
date_default_timezone_set('America/Winnipeg');
$current_timestamp = strtotime('2016-03-13 0'.$i.':00:00'); // 1457856060
// DST start at 03:00 that day, so 60 minutes before the time should be 01:01
$ts = $current_timestamp - 1*60*60;
echo '-3600s: ', $ts, ", ", date('Y-m-d H:i:s', $ts), "\n";
// 1457852460, 2016-10-30 02:59:00, correct
// now let's test strtotime with -1 hour
$ts = strtotime('-1 hour', $current_timestamp);
echo '-1 hour: ', $ts, ", ", date('Y-m-d H:i:s', $ts), "\n";
// 1457856060, 2016-10-30 03:01:00, completely wrong
// DateTime implementation seems smarter:
$dt = new DateTime();
$dt->setTimestamp($current_timestamp);
$dt->sub(new DateInterval('PT1H'));
echo 'sub PT1H: ', $dt->getTimestamp(), ", ", $dt->format('Y-m-d H:i:s'), "\n";
// 1457856060, 2016-10-30 03:01:00, correct
echo "\n\n";
echo 'TS ', $current_timestamp, ", ", date('Y-m-d H:i:s', $current_timestamp), "\n";
echo "\n\n";
}
`
-3600s: 1457848800, 2016-03-13 00:00:00
-1小时:1457848800,2016-03-1300:00:00
sub PT1H: 1457848800, 2016-03-13 00:00:00
TS 1457852400, 2016-03-13 01:00:00
-3600s: 1457852400, 2016-03-13 01:00:00
-1 小时: 1457856000, 2016-03-13 03:00:00
sub PT1H: 1457856000, 2016-03-13 03:00:00
TS 1457856000, 2016-03-13 03:00:00
-3600s: 1457852400, 2016-03-13 01:00:00
-1 小时: 1457856000, 2016-03-13 03:00:00
sub PT1H: 1457856000, 2016-03-13 03:00:00
TS 1457856000, 2016-03-13 03:00:00
-3600s: 1457856000, 2016-03-13 03:00:00
-1 小时: 1457856000, 2016-03-13 03:00:00
sub PT1H: 1457856000, 2016-03-13 03:00:00
TS 1457859600, 2016-03-13 04:00:00
这令人深感困惑。在我的时区,夏令时从 3 月 27 日开始,以下所有表达式 return 相同的 UNIX 时间戳:
var_dump(strtotime("27 March 2016 02:00"));
var_dump(strtotime("- 60 minute", strtotime("27 March 2016 02:00")));
var_dump(strtotime("- 1 hour", strtotime("27 March 2016 02:00")));
var_dump(strtotime("27 March 2016 02:00 - 1 hour"));
var_dump((new DateTime("27 March 2016 02:00"))->format("U"));
var_dump((new DateTime("27 March 2016 02:00"))->sub(new DateInterval("PT1H"))->format("U"));
如果我仔细考虑一下,我可能会相信这是预期的行为。 01:00 3 月 27 日 此处不存在。但这肯定不直观。
更令人困惑的是,从02:00中减去15分钟给出了未来的答案,即02:45。如果你足够眯眼,即使第一个结果有点意义,这个结果也一定是一个错误。
关于这个有an open bug report近4年没有动过。
这给您留下了两个选择。您可以在代码中添加一个 if
子句,如果最初的减法没有减少时间戳,则减去 2 小时或 75 分钟。或者您可以简单地从当前时间戳中减去 3600 或 900 秒,而不是使用 strtotime
。两者都不是特别优雅,但我们就是这样。
似乎 strtotime
不够聪明,无法在对相对值进行操作时考虑 DST 更改:
// let's say current time is this:
date_default_timezone_set('Europe/Berlin');
$current_timestamp = strtotime('2016-10-30 01:59:00'); // 1477785540
// DST ends at 03:00 that day, so 120 minutes later the time should be 02:59
$ts = $current_timestamp + 2*60*60;
echo $ts, ", ", date('Y-m-d H:i:s', $ts), "\n";
// 1477792740, 2016-10-30 02:59:00, correct
// now let's test strtotime with +2 hours
$ts = strtotime('+2 hours', $current_timestamp);
echo $ts, ", ", date('Y-m-d H:i:s', $ts), "\n";
// 1477796340, 2016-10-30 03:59:00, completely wrong
// DateTime implementation seems smarter:
$dt = new DateTime();
$dt->setTimestamp($current_timestamp);
$dt->add(new DateInterval('PT2H'));
echo $dt->getTimestamp(), ", ", $dt->format('Y-m-d H:i:s');
// 1477792740, 2016-10-30 02:59:00, correct
在您的特定情况下,我只是直接比较时间戳(差异显然以秒为单位),但是使用 DateTime
和 TimeInterval
也是一种选择。