为什么php datetime diff取决于时区?

时间:2016-11-01 05:06:20

标签: php date timezone diff intervals

请参阅以下代码:

function printDiff($tz) {
    $d1 = new DateTime("2015-06-01", new DateTimeZone($tz));
    $d2 = new DateTime("2015-07-01", new DateTimeZone($tz));
    $diff = $d1->diff($d2);
    print($diff->format("Year: %Y Month: %M Day: %D"). PHP_EOL);
}
printDiff("UTC");
printDiff("Australia/Melbourne");

结果是:

Year: 00 Month: 01 Day: 00
Year: 00 Month: 00 Day: 30

问题:

  • 两个相邻月份(6月1日和7月)的同一天之间的差异如何不同于1个月?
  • 为什么计算模式取决于我在给定天数之间没有DST时使用哪个时区,没有闰年,没有什么特别之处?
  • 在哪里可以找到算法的确切描述如何计算差异?

1 个答案:

答案 0 :(得分:7)

date 扩展名将时间值存储在GMT中。 GMT偏移is stored separately。它适用于计算的后期阶段,以便进行修正。

特别是,DateTime::diff内部调用timelib_diff函数,它计算两个日期之间的差异,应用DST校正,然后按顺序规范化其内部结构。

如果两个日期都在 UTC 中,则该函数会比较以下内容:

  • Timestamp=1433116800, year=2015, month=6, day=1, hour=0, minute=0, second=0
  • Timestamp=1435708800, year=2015, month=7, day=1, hour=0, minute=0, second=0

相应地减去年,月,日,小时,分钟和秒。差异恰好是一个月。因此,normalization之后不会修改内部结构。

当两个日期都在 Australia / Melbourne 时,该功能会比较以下内容:

  • Timestamp=1433080800, year=2015, month=5, day=31, hour=14, minute=0, second=0
  • Timestamp=1435672800, year=2015, month=6, day=30, hour=14, minute=0, second=0

通过减去10小时(没有DST校正的时区偏移)获得两个日期。正如我们所看到的,如果需要,减去时间值后的DST校正is applied(特别是不需要)。归一化之前的差异是:

0 years, 1 month, -1 day, 0 hours, 0 minutes, 0 seconds

由于我们在月份之间存在偏移,因此规范化函数会将差异计算为

0 years, 0 months, 30 days, 0 hours, 0 minutes, 0 seconds

DateInterval::format方法很简单。它只是将占位符替换为timelib_rel_time结构的成员。这就是为什么我们为UTC提供 1个月,为澳大利亚/墨尔本提供 30天的原因。

a格式字符

这看起来有点不可靠。但是,days结构中有timelib_rel_time个成员,always equals to the difference in days。该值可通过a格式字符获得:

function printDiff($tz) {
  $d1 = new DateTime("2015-06-01", new DateTimeZone($tz));
  $d2 = new DateTime("2015-07-01", new DateTimeZone($tz));
  $diff = $d1->diff($d2);
  print($diff->format("Year: %Y Month: %M Day: %D days: %a"). PHP_EOL);
}

printDiff("UTC");
printDiff("Australia/Melbourne");

输出

Year: 00 Month: 01 Day: 00 days: 30
Year: 00 Month: 00 Day: 30 days: 30

<强> P.S。

此答案中的值是在TIMELIB_DEBUG宏的帮助下获得的。