请参阅以下代码:
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时使用哪个时区,没有闰年,没有什么特别之处?
>在哪里可以找到算法的确切描述如何计算差异?
解决方法:
日期扩展名将时间值存储在GMT中. GMT偏移is stored separately.它在计算的后期阶段应用,用于校正.
特别是,DateTime :: diff内部调用timelib_diff
函数,它计算两个日期之间的差异,应用DST校正,然后按顺序规范化其内部结构.
当两个日期都是UTC时,该函数会比较以下内容:
>时间戳= 1433116800,年= 2015,月= 6,日= 1,小时= 0,分钟= 0,秒= 0
>时间戳= 1435708800,年= 2015,月= 7,日= 1,小时= 0,分钟= 0,秒= 0
它相应地减去年,月,日,小时,分钟和秒.差异恰好是一个月.因此,在normalization之后不会修改内部结构.
当这两个日期都在澳大利亚/墨尔本时,该功能会比较以下内容:
>时间戳= 1433080800,年= 2015,月= 5,日= 31,小时= 14,分钟= 0,秒= 0
>时间戳= 1435672800,年= 2015,月= 6,日= 30,小时= 14,分钟= 0,秒= 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天的原因.
一个格式字符
这看起来有点不可靠.但是,timelib_rel_time结构中有一个days成员,即always equals to the difference in days.该值可通过格式字符获得:
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
附:
此答案中的值是在TIMELIB_DEBUG
宏的帮助下获得的.