简体   繁体   English

filemtime 可以在夏令时与 strtotime 进行比较吗?

[英]Can filemtime be compared with strtotime at the daylight savings change?

I have some PHP code to send warnings and automatically shut down a service if the source data files are out of date.如果源数据文件过期,我有一些 PHP 代码可以发送警告并自动关闭服务。 This is done using the following comparisons:这是使用以下比较完成的:

Warning: filemtime($file_location) < strtotime('-15 minute')警告: filemtime($file_location) < strtotime('-15 minute')

Consider service down: filemtime($file_location) < strtotime('-1 hour')考虑服务停机: filemtime($file_location) < strtotime('-1 hour')

For 1 hour beginning at 3:00 AM CDT when daylight savings time begins, this incorrectly reports the file as being over 15 minutes old.对于夏令时开始时 CDT 凌晨 3:00 开始的 1 小时,这会错误地将文件报告为超过 15 分钟。 Toward the end of the hour, it also incorrectly reports the file as being more than 1 hour old.快要结束时,它还会错误地将文件报告为超过 1 小时。 At 4:00 AM CDT things return to normal. CDT 凌晨 4:00 一切恢复正常。

Is there something I don't know about either the filemtime() or strtotime() functions that would explain this behaviour?有什么我不知道的关于 filemtime() 或 strtotime() 函数可以解释这种行为吗? It's my understanding that both return UNIX timestamps, and that timestamps are by definition in UTC, so I'm not sure what could cause this problem.我的理解是两者都返回 UNIX 时间戳,并且时间戳是按照 UTC 定义的,所以我不确定是什么导致了这个问题。

Based on the answers so far, I ran this test on our server:根据到目前为止的答案,我在我们的服务器上运行了这个测试:

` `

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 -3600s: 1457848800, 2016-03-13 00:00:00

-1 hour: 1457848800, 2016-03-13 00:00:00 -1 小时:1457848800,2016-03-13 00:00:00

sub PT1H: 1457848800, 2016-03-13 00:00:00子 PT1H: 1457848800, 2016-03-13 00:00:00

TS 1457852400, 2016-03-13 01:00:00 TS 1457852400, 2016-03-13 01:00:00

-3600s: 1457852400, 2016-03-13 01:00:00 -3600s: 1457852400, 2016-03-13 01:00:00

-1 hour: 1457856000, 2016-03-13 03:00:00 -1 小时:1457856000,2016-03-13 03:00:00

sub PT1H: 1457856000, 2016-03-13 03:00:00子 PT1H: 1457856000, 2016-03-13 03:00:00

TS 1457856000, 2016-03-13 03:00:00 TS 1457856000, 2016-03-13 03:00:00

-3600s: 1457852400, 2016-03-13 01:00:00 -3600s: 1457852400, 2016-03-13 01:00:00

-1 hour: 1457856000, 2016-03-13 03:00:00 -1 小时:1457856000,2016-03-13 03:00:00

sub PT1H: 1457856000, 2016-03-13 03:00:00子 PT1H: 1457856000, 2016-03-13 03:00:00

TS 1457856000, 2016-03-13 03:00:00 TS 1457856000, 2016-03-13 03:00:00

-3600s: 1457856000, 2016-03-13 03:00:00 -3600s: 1457856000, 2016-03-13 03:00:00

-1 hour: 1457856000, 2016-03-13 03:00:00 -1 小时:1457856000,2016-03-13 03:00:00

sub PT1H: 1457856000, 2016-03-13 03:00:00子 PT1H: 1457856000, 2016-03-13 03:00:00

TS 1457859600, 2016-03-13 04:00:00 TS 1457859600, 2016-03-13 04:00:00

That's deeply confusing.这令人深感困惑。 In my timezone, where daylight savings begins on 27 March, all of the following expressions return the same UNIX timestamp:在我的时区,夏令时从 3 月 27 日开始,以下所有表达式都返回相同的 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"));

If I think hard enough about this, I could perhaps believe it's the intended behaviour.如果我对此足够认真,我也许可以相信这是预期的行为。 01:00 on 27 March does not exist here . 3 月 27 日 01:00此处不存在 But it's certainly not intuitive.但这肯定不是直观的。

Even more confusingly, subtracting 15 minutes from 02:00 gives an answer in the future , namely 02:45.更让人困惑的是,从02:00减去15分钟就得到了未来的答案,即02:45。 Even if the first result makes a little sense if you squint enough, this result has got to be a bug.即使第一个结果在你眯得足够远的情况下有点意义,但这个结果肯定是一个错误。

There is an open bug report about this which has been untouched for nearly 4 years.一个关于此的公开错误报告,该报告已近 4 年未受影响。

This leaves you with two choices.这给您留下了两个选择。 You could add an if clause to your code, subtracting 2 hours or 75 minutes if the initial subtraction doesn't decrease the timestamp.您可以在代码中添加一个if子句,如果初始减法没有减少时间戳,则减去 2 小时或 75 分钟。 Or you could simply subtract 3600 or 900 seconds from the current timestamp instead of using strtotime .或者您可以简单地从当前时间戳中减去 3600 或 900 秒,而不是使用strtotime Neither is particularly elegant, but there we are.两者都不是特别优雅,但我们就是这样。

Seems like strtotime is not smart enough to take DST changes into consideration when operating on relative values:似乎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

In your particular case I'd simply compare the timestamps directly (the difference would be in seconds, obviously), but using DateTime with TimeInterval is an option, too.在您的特定情况下,我只是直接比较时间戳(显然,差异将以秒为单位),但将DateTimeTimeInterval一起使用也是一种选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM