获取以下 PHP 代码:
<?php
$timezone = new DateTimeZone('UTC');
$startDate = new DateTime('2022-09-26T00:00:00', $timezone);
$endDate1 = new DateTime('2023-02-28T00:00:00', $timezone);
$endDate2 = new DateTime('2023-03-01T00:00:00', $timezone);
$interval1 = $endDate1->diff($startDate);
$interval2 = $endDate2->diff($startDate);
print_r($interval1);
print_r($interval2);
这是输出:
DateInterval Object
(
[y] => 0
[m] => 5
[d] => 2
[h] => 0
[i] => 0
[s] => 0
[f] => 0
[weekday] => 0
[weekday_behavior] => 0
[first_last_day_of] => 0
[invert] => 1
[days] => 155
[special_type] => 0
[special_amount] => 0
[have_weekday_relative] => 0
[have_special_relative] => 0
)
DateInterval Object
(
[y] => 0
[m] => 5
[d] => 5
[h] => 0
[i] => 0
[s] => 0
[f] => 0
[weekday] => 0
[weekday_behavior] => 0
[first_last_day_of] => 0
[invert] => 1
[days] => 156
[special_type] => 0
[special_amount] => 0
[have_weekday_relative] => 0
[have_special_relative] => 0
)
有人可以解释为什么当
y-m-d
计数为 155 时,第一个间隔的 days
是 0-5-2,但第二个间隔的
y-m-d
是 0-5-5,即使只添加了 1 天(事实上days
计数为 156)?
我尝试用其他语言(准确地说是 JavaScript 和 Python)移植相同的代码,第一个时间间隔的结果与 PHP 的结果相同:5 个月零 2 天。 然而,第二个间隔的结果是 5 个月又 3 天(正如我所期望的),而不是 PHP 所说的 5 个月又 5 天。
PHP 通过简单地计算时间戳所有组成部分之间的差异来找到两个日期之间的差异。 (年、月、日等 (ref))因此,在这个阶段,第二个间隔看起来像
(y=1, m=-6, d=-25)
。然而,这对我们人类来说没有什么意义,因此如果下一个字段会溢出或下溢,PHP 会尝试通过调整每个字段来标准化此间隔。 (参考)。但是月份不包含一致的天数,因此 PHP 尝试变得聪明,并根据我们开始的月份的长度进行逐月调整。(ref)
因此,如果第一个日期是 2 月,则 days 字段将调整 28 天:
(y=1, m=-7, d=2)
,而 3 月有 31 天,产生 (y=1, m=-7, d=5)
。这两个间隔的下一步是月份调整,这是相同的。一年有十二个月,所以我们得到 (y=0, m=5, d=2)
和 (y=0, m=5, d=5)
。
知道了这一点,我们就可以从奇怪的 PHP 中获得更多乐趣了
$start = new DateTime('2022-09-26');
$end = new DateTime('2023-03-01');
$start->diff($end); // +5m 3d
$end->diff($start); // -5m 5d
编辑:我对 PHP 内部工作方式的第一个假设被证明是不正确的,因此在 @KIKO Software 提出他们的问题后,上面的答案已被重写。