【问题标题】:PHP: Subtracting 1 hour from the Dailight Savings Time one hour after the changeoverPHP:转换后一小时从夏令时减去 1 小时
【发布时间】:2020-09-12 09:41:59
【问题描述】:

我在 PHP 中遇到了一件奇怪的事情。在Europe/Oslo 时区中,我从时间戳2020-03-29 03:00:00 中减去一小时(这正是Dailight Savings Time shift 发生的时间),结果是完全相同的时间戳2020-03-29 03:00:00!它应该导致2020-03-29 01:00:00。怎么没有?

一直到2020-03-29 03:59:59,它在减去一小时时返回完全相同的时间戳(尝试了sub()modify())。之后的下一秒,它会正确生成2020-03-29 03:00:00

你可以像这样复制它:

date_default_timezone_set('Europe/Oslo');
echo (new \DateTime('2020-03-29 03:00:00'))->sub(new \DateInterval('PT1H'))->format('Y-m-d H:i:s');

我在 PHP 7.1.33、7.3.10 和 7.3.18 中都对此进行了测试。

附言。不过,在2020-03-29 01:00:00 上加 1 小时确实正确地给出了2020-03-29 03:00:00

【问题讨论】:

  • This info 似乎与您的描述有关。
  • 问题是,Datetime 对象带有时区。 DST 当天凌晨 2 点,时钟立即切换到 3 点。通过从凌晨 3 点减去 1 小时,您将在凌晨 2 点出来 - 如果您随后在奥斯陆时区格式化此日期时间,它会神奇地再次移动到凌晨 3 点......欢迎来到暮光区!

标签: php datetime dst


【解决方案1】:

虽然我同意这是不良/错误的行为,但您可以通过严格只在 UTC 中存储或计算日期来避免它。考虑到时区仅用于显示目的,您将避免很多令人头疼的问题。

例如:

// input
$utc     = new DateTimeZone('UTC');
$user_tz = new DateTimeZone('Europe/Oslo');
$input   = new DateTime('2020-03-29 03:00:00', $user_tz);
$storage = (clone $input)->setTimezone($utc);
var_dump(
    $input->format('c'),
    $storage->format('c')
);

// compute
$interval = new DateInterval('PT1H');
$storage->sub($interval);
var_dump(
    $storage->format('c')
);

// display
$display = (clone $storage)->setTimezone($user_tz);
var_dump(
    $display->format('c')
);

输出:

string(25) "2020-03-29T03:00:00+02:00"
string(25) "2020-03-29T01:00:00+00:00"
string(25) "2020-03-29T00:00:00+00:00"
string(25) "2020-03-29T01:00:00+01:00"

【讨论】:

  • 好点。我通常以 UTC 存储,但在这里我处理大量的每小时记录数据,我们正在对这些数据进行统计 SQL 查询。因此,如果我们不将数据保存在本地时区,那么这些天/小时分组查询将非常困难。当然可以在 PHP 中进行算术运算之前将其转换为 UTC...
猜你喜欢
  • 2014-05-23
  • 2018-10-01
  • 2021-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-24
  • 1970-01-01
  • 2012-09-27
相关资源
最近更新 更多