为什么 php 日期时间差异取决于时区?
Why does php datetime diff depend on time zones?
见以下代码:
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 个月?
- 如果给定日期之间没有夏令时,没有闰年,没有什么特别之处,为什么计算模式取决于我使用的时区?
- 我在哪里可以找到关于如何计算差值的算法的准确描述?
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
结构的成员。这就是为什么我们得到 1 个月 的 UTC,30 天 的 Australia/Melbourne.
a
格式字符
这看起来有点不靠谱。但是,timelib_rel_time
结构中有一个days
成员,即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
宏的帮助下获得的。
见以下代码:
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 个月?
- 如果给定日期之间没有夏令时,没有闰年,没有什么特别之处,为什么计算模式取决于我使用的时区?
- 我在哪里可以找到关于如何计算差值的算法的准确描述?
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
结构的成员。这就是为什么我们得到 1 个月 的 UTC,30 天 的 Australia/Melbourne.
a
格式字符
这看起来有点不靠谱。但是,timelib_rel_time
结构中有一个days
成员,即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
宏的帮助下获得的。