PHP DateTime->diff方法计算时间差间歇性显示错误问题求助
问题排查:间歇性错误显示“1 day ago”的根源
嘿,这个间歇性bug的原因其实很明确——你在创建DateTime对象时误用了12小时制的小时格式符h,而不是24小时制的H!这就是导致错误的元凶。
为什么会出现这个问题?
当$RawDate对应的是UTC时间的下午时段(12:00-23:59),date("Y-m-d h:i:s", $RawDate)会把小时部分转成1-12的12小时制格式(比如14:26会变成02:26),但这个格式化后的字符串没有AM/PM标识。DateTime类在解析这种不带AM/PM的12小时制时间时,默认会把它当成上午的时间,这就导致你创建的$DateObject比实际事件时间早了整整12小时。
举个具体的例子:
- 实际事件时间:
2021-06-18 14:26:31 UTC(对应某个时间戳) - 用
h格式化后得到字符串:2021-06-18 02:26:31 DateTime解析后得到的对象:2021-06-18 02:26:31 UTC(比实际时间早12小时)
如果当前时间是2021-06-19 11:00:00 UTC:
- 实际时间差是20小时33分(还没到24小时,应该显示
20 hours ago) - 但错误的
DateObject和当前时间的差是32小时33分(超过24小时),这时候diff返回的d属性会变成1,导致错误输出1 day ago
当当前时间继续推进到实际事件时间的24小时后,错误的显示和正确结果巧合一致,你就会误以为“恢复正常”了——但这只是偶然,问题根源并没有解决。
修复方案
只需要把创建DateTime对象那一行里的h改成H(24小时制格式符),这样格式化后的时间字符串是正确的24小时制,DateTime就能准确解析出事件的真实时间:
// 关键修复:将h替换为H,使用24小时制格式化时间戳 $DateObject = new DateTime(date("Y-m-d H:i:s", $RawDate));
额外优化建议
其实你完全不需要先用date()格式化时间戳,DateTime类可以直接接受带@前缀的时间戳作为构造参数,这样更高效还能彻底避免格式符用错的问题:
// 直接用时间戳创建UTC时区的DateTime对象,更简洁准确 $DateObject = new DateTime("@$RawDate"); $DateObject->setTimezone(new DateTimeZone('UTC'));
修复后的完整代码:
<?php function TimeAgo($RawDate) { global $G_CurrentTime; $TimeAgoString = ''; // 优化后的写法:直接用时间戳创建UTC时区的DateTime对象 $DateObject = new DateTime("@$RawDate"); $DateObject->setTimezone(new DateTimeZone('UTC')); $DateDiff = $G_CurrentTime->diff($DateObject); $TimeAgoArray = (array)$DateDiff; print_r($G_CurrentTime); print_r($DateObject); print_r($TimeAgoArray); // years if ($TimeAgoArray['y'] > 0) { $YearString = 'year'; $TimeAgoString = $TimeAgoArray['y'] . ' ' . ($TimeAgoArray['y'] > 1 ? $YearString . 's' : $YearString) . ' ago'; } // months else if ($TimeAgoArray['m'] > 0) { $MonthString = 'month'; $TimeAgoString = $TimeAgoArray['m'] . ' ' . ($TimeAgoArray['m'] > 1 ? $MonthString . 's' : $MonthString) . ' ago'; } // days else if ($TimeAgoArray['d'] > 0) { $DayString = 'day'; $TimeAgoString = $TimeAgoArray['d'] . ' ' . ($TimeAgoArray['d'] > 1 ? $DayString . 's' : $DayString) . ' ago'; } // hours else if ($TimeAgoArray['h'] > 0) { $HourString = 'hour'; $TimeAgoString = $TimeAgoArray['h'] . ' ' . ($TimeAgoArray['h'] > 1 ? $HourString . 's' : $HourString) . ' ago'; } // minutes else if ($TimeAgoArray['i'] > 0) { $MinuteString = 'minute'; $TimeAgoString = $TimeAgoArray['i'] . ' ' . ($TimeAgoArray['i'] > 1 ? $MinuteString . 's' : $MinuteString) . ' ago'; } // seconds else if ($TimeAgoArray['s'] > 0) { $SecondString = 'second'; $TimeAgoString = $TimeAgoArray['s'] . ' ' . ($TimeAgoArray['s'] > 1 ? $SecondString . 's' : $SecondString) . ' ago'; } // just now else { $TimeAgoString = 'just now'; } return $TimeAgoString; } ?>
内容的提问来源于stack exchange,提问作者PHPisMyFavLol
相关产品推荐
相关产品推荐

