php date_diff 错误与 2021-12-01 而不是 UTC 时区
进行 diff 然后将其应用到相同的日期,结果我们希望看到相同的日期,但结果可能是不可预测的。
在 php 8.0.16、7.4.7 上测试
<?php
date_default_timezone_set('Europe/Amsterdam');
$dateTimeNow = new DateTimeImmutable('2022-03-18 00:00:00.000000');
$dateTimeOld = new DateTimeImmutable('2021-12-01 00:00:00.000000');
$timeInterval = $dateTimeOld->diff($dateTimeNow);
var_dump($dateTimeNow); //output 2022-03-18
var_dump($dateTimeOld->add($timeInterval)); //output 2022-03-16 but must be 2022-03-18!
$dateTimeNow = new DateTimeImmutable('2022-03-01 00:00:00.000000');
$dateTimeOld = new DateTimeImmutable('2021-12-01 00:00:00.000000');
$timeInterval = $dateTimeOld->diff($dateTimeNow);
var_dump($dateTimeNow); //output 2022-03-01
var_dump($dateTimeOld->add($timeInterval)); //output 2022-03-02 but must be 2022-03-01!
date_default_timezone_set('UTC');
$dateTimeNow = new DateTimeImmutable('2022-03-18 00:00:00.000000');
$dateTimeOld = new DateTimeImmutable('2021-12-01 00:00:00.000000');
$timeInterval = $dateTimeOld->diff($dateTimeNow);
var_dump($dateTimeNow); //output 2022-03-18
var_dump($dateTimeOld->add($timeInterval)); //output 2022-03-18 correct!
$dateTimeNow = new DateTimeImmutable('2022-03-01 00:00:00.000000');
$dateTimeOld = new DateTimeImmutable('2021-12-01 00:00:00.000000');
$timeInterval = $dateTimeOld->diff($dateTimeNow);
var_dump($dateTimeNow); //output 2022-03-01
var_dump($dateTimeOld->add($timeInterval)); //output 2022-03-01 correct!
注意。在 php 8.1.3 上运行没有 bug
如何解释,以及应该做什么我用于此目的是为了确保它有效且稳定
Make diff and then apply it to the same date, in result we want to see the same date, but result can be unpredictable.
Tested on php 8.0.16, 7.4.7
<?php
date_default_timezone_set('Europe/Amsterdam');
$dateTimeNow = new DateTimeImmutable('2022-03-18 00:00:00.000000');
$dateTimeOld = new DateTimeImmutable('2021-12-01 00:00:00.000000');
$timeInterval = $dateTimeOld->diff($dateTimeNow);
var_dump($dateTimeNow); //output 2022-03-18
var_dump($dateTimeOld->add($timeInterval)); //output 2022-03-16 but must be 2022-03-18!
$dateTimeNow = new DateTimeImmutable('2022-03-01 00:00:00.000000');
$dateTimeOld = new DateTimeImmutable('2021-12-01 00:00:00.000000');
$timeInterval = $dateTimeOld->diff($dateTimeNow);
var_dump($dateTimeNow); //output 2022-03-01
var_dump($dateTimeOld->add($timeInterval)); //output 2022-03-02 but must be 2022-03-01!
date_default_timezone_set('UTC');
$dateTimeNow = new DateTimeImmutable('2022-03-18 00:00:00.000000');
$dateTimeOld = new DateTimeImmutable('2021-12-01 00:00:00.000000');
$timeInterval = $dateTimeOld->diff($dateTimeNow);
var_dump($dateTimeNow); //output 2022-03-18
var_dump($dateTimeOld->add($timeInterval)); //output 2022-03-18 correct!
$dateTimeNow = new DateTimeImmutable('2022-03-01 00:00:00.000000');
$dateTimeOld = new DateTimeImmutable('2021-12-01 00:00:00.000000');
$timeInterval = $dateTimeOld->diff($dateTimeNow);
var_dump($dateTimeNow); //output 2022-03-01
var_dump($dateTimeOld->add($timeInterval)); //output 2022-03-01 correct!
NOTE. On php 8.1.3 works without bug
How can it be explained, and what should i use for this purpose to be sure it is valid and stable
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
因此,我将您的代码重新排列为:
Whichoutputs in php>=8.1:
和 in php <8.1:
这似乎在
DateTime->diff()
或DateInterval
上有所不同代码> 定义“一个月”。我敢打赌,这种差异与时区数据和/或 DST 转换有关,因此 UTC 和阿姆斯特丹 TZ 之间存在差异。我这里的首选解决方案始终是“始终以 UTC 存储和计算日期,所有其他时区都只是为了人类的眼球”。
但如果这不是一个可行的要求,那么对于这种特定情况,您不处理比几天更细化的事情,您可能可以逃脱:
这应该消除模糊的问题“月份和剩余天数”并仅保留“总天数”,这样可以在所有当前 PHP 版本中提供一致的结果。但是,如果在您的实际代码中存在时间组件,那么您将不得不欺骗该格式调用以生成正确的间隔规范。
8.1 版本中的日期错误修复清单,但我无法告诉您其中哪一个适用。
So I rearranged your code to:
Which outputs in php>=8.1:
and in php <8.1:
Which appears to differ on how either
DateTime->diff()
orDateInterval
define 'a month'. I would wager that that difference has something to do with the timezone data and/or DST transition, hence the difference between UTC and Amesterdam TZs.My go-to solution here is always going to be "always store and compute dates in UTC, all other timezones are simply for human eyeballs".
But if that is not a feasible ask, then for this specific situation where you're not dealing with anything more granular than a number of days, you can probably get away with:
Which should strip out the nebulous "months and remainder days" and leave only the "total days", which gives consistent results across all current PHP versions. But if, in your actual code, there is a time component then you're going to have to finagle that format call to produce the correct interval spec.
There is a laundry list of Date bugfixes in the 8.1 release but I couldn't tell you which of these is applicable.