You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP中DateTime类在夏令时场景下的日期时间比较问题

PHP 夏令时场景下 DateTime 日期时间比较问题解决方案

问题复现

测试代码如下:

$timezone = "America/New_York";

$date1 = new DateTime('2021-11-07 01:55:00.000000', new DateTimeZone($timezone));
$date1->add(new DateInterval("PT5M"));
$date2 = new DateTime('2021-11-07 01:55:00.000000', new DateTimeZone($timezone));

/*
$date1 = 2021-11-07 01:00:00.000000
$date2 = 2021-11-07 01:55:00.000000
*/
var_dump($date1 > $date2);
/*
result: bool(true)
*/

原因说明

2021年11月7日是美国纽约时区的夏令时结束日,当日凌晨2点会回拨1小时到1点,因此当天存在两个重叠的1点区间:

  • 第一个1点属于夏令时,对应UTC时间为UTC-4
  • 第二个1点属于冬令时,对应UTC时间为UTC-5
    代码中$date1加5分钟后触发夏令时切换,落入冬令时的1点区间,实际内部存储的UTC时间戳比$date2大。PHP中DateTime对象比较默认使用内部存储的UTC时间戳,而非表面显示的本地时间字符串,因此返回true属于符合底层逻辑的正常结果。

处理方案

  • 统一使用UTC时间进行所有日期计算、比较操作,仅在需要给用户展示的时候转换为本地时区。
    示例:
    // 所有计算都用UTC时区,输出时再转本地
    $date1 = new DateTime('2021-11-07 01:55:00.000000', new DateTimeZone($timezone));
    $date1->setTimezone(new DateTimeZone('UTC'));
    $date1->add(new DateInterval("PT5M"));
    $date2 = new DateTime('2021-11-07 01:55:00.000000', new DateTimeZone($timezone));
    $date2->setTimezone(new DateTimeZone('UTC'));
    var_dump($date1 > $date2); // 结果依然为true,符合实际时间先后逻辑
    
  • 如果业务需要按本地显示的字面时间比较,可以提取两个DateTime的本地时间字符串,重新以UTC时区创建对象后再比较:
    $date1Str = $date1->format('Y-m-d H:i:s');
    $date2Str = $date2->format('Y-m-d H:i:s');
    $date1Literal = new DateTime($date1Str, new DateTimeZone('UTC'));
    $date2Literal = new DateTime($date2Str, new DateTimeZone('UTC'));
    var_dump($date1Literal > $date2Literal); // 返回false,符合字面时间的比较预期
    
  • 涉及时间增减操作优先使用DateTimeImmutable类,避免原对象被意外修改,同时可以明确控制每一步的时间转换逻辑。

内容的提问来源于stack exchange,提问作者O. Batista

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 20:36:08