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

Cso*_*mai 6 php diff timezone date 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");
Run Code Online (Sandbox Code Playgroud)

结果是:

Year: 00 Month: 01 Day: 00
Year: 00 Month: 00 Day: 30
Run Code Online (Sandbox Code Playgroud)

问题:

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

Rus*_*nov 8

日期延长以GMT存储时间值。GMT偏移量单独存储。它在计算的后期应用,以进行校正。

特别是,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

它分别减去年,月,日,小时,分钟和秒。区别仅是一个月。因此,标准化后内部结构不会被修改。

当两个日期都在澳大利亚/墨尔本时,该函数将进行以下比较:

  • 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校正。归一化之前的区别是:

0 years, 1 month, -1 day, 0 hours, 0 minutes, 0 seconds
Run Code Online (Sandbox Code Playgroud)

由于我们在月份之间存在偏移,因此归一化函数将差计算为

0 years, 0 months, 30 days, 0 hours, 0 minutes, 0 seconds
Run Code Online (Sandbox Code Playgroud)

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

a格式字符

看起来有些不可靠。然而,有一个days在成员timelib_rel_time结构,它总是等于在天的差别。该值可通过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");
Run Code Online (Sandbox Code Playgroud)

输出量

Year: 00 Month: 01 Day: 00 days: 30
Year: 00 Month: 00 Day: 30 days: 30
Run Code Online (Sandbox Code Playgroud)

聚苯乙烯

此答案中的值是借助TIMELIB_DEBUG宏获得的。