问题描述
function time_is_older_than($timestamp,$time_string)
{
if (strtotime($timestamp) < strtotime('-' . $time_string))
return true;
return false;
}
function time_is_younger_than($timestamp,$time_string)
{
if (strtotime($timestamp) > strtotime('-' . $time_string))
return true;
return false;
}
它们使我能够做以下整洁的事情:
if (time_is_older_than($last_time_some_action_happened,'5 minutes'))
do_it_again();
当我的时区切换为“夏令时”或“冬季”时,他们通常工作, 每六个月工作一小时时间”。这意味着时钟会增加或推迟到午夜一小时(根据该时区)。
PHP手册针对strtotime
声明了这一点:
此函数返回的Unix时间戳不包含有关时区的信息。为了使用日期/时间信息进行计算,您应该使用功能更强大的DateTimeImmutable。
但是,如果我提供了完全相同的日期/时间字符串,例如在末尾添加了“ +08:00”与“ +00:00”,则返回的秒数不同。因此strtotime()
在解析提供的时间时确实理解了时区,即使返回的整数显然不包含此信息也是如此。 (不是我期望或要求的。)
我花了无数小时试图调试它,测试无数事物,并且只是坐在这里思考,但是我无法弄清楚到底什么会使我的代码失败,特别是一小时。尤其是我需要更改的内容。为strtotime()
设置第二个参数似乎是可能的,但我只是无法使其正常工作。
一段时间以来,我最热的“线索”是strtotime('-' . $time_string)
部分使用的时区与提供的时间戳字符串不同,但是我确实在大多数时间提供时区数据! $last_time_some_action_happened
的示例可能类似于2020-10-28 02:22:41.123456+01
。
我将时区设置为date_default_timezone_set()
。
我怀疑我只需要做一些很小的改动,但是现在我已经进行了这么长时间的实验,即使休息了一段时间,我的大脑也无法清楚地看到这一点。我敢打赌,解决方案非常简单。
请不要告诉我使用DateTimeImmutable
。这将从根本上改变我的整个结构,并要求我做事大不相同。也许在某个时候我应该,甚至会,但是就目前而言,我只想修复现有代码中这个罕见但仍然非常烦人的错误。 (如果有可能,我非常相信是这种情况。)
解决方法
我能够重现您遇到的问题:
date_default_timezone_set('Pacific/Auckland');
// Daylight saving time 2020 in New Zealand began at 2:00am on Sunday,27 September
$current = strtotime('2020-09-27 02:04:00');
$d1 = strtotime('2020-09-27 02:05:00',$current);
$d2 = strtotime('-5 minutes',$current);
var_dump($d1 > $d2); // false
var_dump(date('Y-m-d H:i:s',$d1)); // 2020-09-27 03:05:00
var_dump(date('Y-m-d H:i:s',$d2)); // 2020-09-27 03:59:00
此人看起来与您有相同的问题,可能似乎是错误。 DateTime::modify and DST switch 解决方案是将日期转换为UTC,然后进行比较:
// Convert to UTC and compare
$d1 = new \DateTime('2020-09-27 02:05:00',new \DateTimeZone('Pacific/Auckland'));
$d2 = new \DateTime('2020-09-27 02:04:00',new \DateTimeZone('Pacific/Auckland'));
$d2->setTimezone(new \DateTimeZone('UTC'));
$d2->modify('-5 minutes');
$d2->setTimezone(new \DateTimeZone('Pacific/Auckland'));
var_dump($d1 > $d2); // true
var_dump($d1->format(\DateTimeInterface::RFC3339_EXTENDED)); // 2020-09-27T03:05:00.000+13:00
var_dump($d2->format(\DateTimeInterface::RFC3339_EXTENDED)); // 2020-09-27T01:59:00.000+12:00
我已经更新了您的功能:
function time_is_older_than($datetime,$time_string)
{
$d1 = new \DateTime($datetime);
$d1->setTimezone(new \DateTimeZone('UTC'));
$d2 = new \DateTime();
$d2->setTimezone(new \DateTimeZone('UTC'));
$d2->modify('-' . $time_string);
return $d1 < $d2;
}
function time_is_younger_than($datetime,$time_string)
{
$d1 = new \DateTime($datetime);
$d1->setTimezone(new \DateTimeZone('UTC'));
$d2 = new \DateTime();
$d2->setTimezone(new \DateTimeZone('UTC'));
$d2->modify('-' . $time_string);
return $d1 > $d2;
}
,
您可以考虑以下解决方案: 在时间戳字符串中(例如Thu,2000年12月21日16:01:07 +0200),添加一个时区标记,该标记指定时区,且不夏时制。