PHP 8.1中date_modify返回负微秒问题求助
PHP 8.1负微秒日期时间异常的原因解析
这个问题是PHP 8.1版本中DateTime类处理毫秒减法时的精度计算bug,仅在特定条件下触发:当原时间的微秒值极小(如1微秒),且执行的减法操作会导致微秒部分出现负数时,DateTime内部未正确执行向秒位的借位修正逻辑。
具体触发逻辑拆解
- 当
DateTime对象的微秒设为1(即0.000001秒),执行modify('-100 ms')时,实际是减去0.1秒(等于100000微秒)。 - 计算时微秒部分直接得到
1 - 100000 = -99999,而正常逻辑中,这种负数微秒应该触发向秒位借1:秒数减1,微秒部分加上1000000(1秒对应的微秒数),最终得到01:01:00.900001。 - 但PHP 8.1的
DateTime未处理这个借位,直接保留了负的微秒值,导致用u格式化符输出时出现.-99999的异常结果。
验证代码及异常输出
触发问题的测试代码:
$datetime_before = date_create('now'); $datetime_before->setTime(1,1,1,1); // 微秒设为1时触发bug $datetime_after = clone($datetime_before); $datetime_after->modify('-100 ms'); $string = $datetime_after->format('Y-m-d H:i:s.u'); if (str_contains($string, "-999")) { echo 'before: '; var_dump($datetime_before); echo PHP_EOL; echo 'after: '; var_dump($datetime_after); echo PHP_EOL; exit; }
异常输出:
before: object(DateTime)#51 (3) { ["date"]=> string(26) "2023-06-02 01:01:01.000001" ["timezone_type"]=> int(3) ["timezone"]=> string(13) "Europe/London" } after: object(DateTime)#52 (3) { ["date"]=> string(26) "2023-06-02 01:01:01.-99999" ["timezone_type"]=> int(3) ["timezone"]=> string(13) "Europe/London" }
版本修复情况
该bug已在PHP 8.2及后续版本中被修复,相同代码在高版本PHP中会输出正确的日期时间字符串。
内容的提问来源于stack exchange,提问作者Adam Edney
相关产品推荐
相关产品推荐

