DateTime::createFromFormat随机失败的原因是什么?
为什么DateTime::createFromFormat有时成功有时失败?
问题场景
在Yii2项目中遇到DateTime解析不稳定的问题,为此编写了以下测试脚本:
<?php $microtime = microtime(true); echo $microtime . PHP_EOL; $now = DateTime::createFromFormat('U.u', $microtime); if (!$now): echo "DateTime::createFromFormat failed..." . PHP_EOL; exit(1); endif; echo $now->format("m-d-Y H:i:s.u") . PHP_EOL;
测试运行结果
连续多次运行脚本,结果时成功时失败:
[test@my-dev-1 ~]$ php test.php 1665274706.459722 10-09-2022 00:18:26.459722 [test@my-dev-1 ~]$ php test.php 1665274708.4653969 DateTime::createFromFormat failed... [test@my-dev-1 ~]$ php test.php \1665274721.9026799 DateTime::createFromFormat failed... [test@my-dev-1 ~]$ php test.php 1665274723.7216589 DateTime::createFromFormat failed... [test@my-dev-1 ~]$ php test.php 1665274724.6398611 DateTime::createFromFormat failed... [test@my-dev-1 ~]$ php test.php 1665274725.429971 10-09-2022 00:18:45.429971 [test@my-dev-1 ~]$ php test.php 1665274726.474606 10-09-2022 00:18:46.474606 [test@my-dev-1 ~]$ php test.php 1665274727.37256 10-09-2022 00:18:47.372560 [test@my-dev-1 ~]$ php test.php 1665274728.3463521 DateTime::createFromFormat failed... [test@my-dev-1 ~]$ php test.php 1665274729.4645841 DateTime::createFromFormat failed... [test@my-dev-1 ~]$ php test.php 1665274730.809057 10-09-2022 00:18:50.809057
服务器环境
- 系统:CentOS Linux release 7.9.2009 (Core)
- PHP版本:
PHP 7.4.32 (cli) (built: Sep 28 2022 09:09:55) ( NTS )
原因分析
问题出在microtime(true)的输出格式与DateTime::createFromFormat使用的U.u格式不匹配:
U.u格式中,U代表Unix时间戳(整数部分),u代表6位微秒数microtime(true)返回的是浮点数,当系统提供的精度超过6位时,输出的字符串会包含7位小数(比如1665274708.4653969),此时u无法匹配7位小数,导致解析失败- 当输出的小数部分≤6位时(比如
1665274706.459722或1665274727.37256),u可以正确匹配(不足6位时会自动补0),所以解析成功
解决方案
确保传入DateTime::createFromFormat的时间字符串小数部分固定为6位,修改测试脚本如下:
<?php $microtime = microtime(true); echo $microtime . PHP_EOL; // 格式化时间戳为6位小数的字符串,保证与U.u格式匹配 $formattedTime = sprintf("%.6f", $microtime); $now = DateTime::createFromFormat('U.u', $formattedTime); if (!$now): echo "DateTime::createFromFormat failed..." . PHP_EOL; exit(1); endif; echo $now->format("m-d-Y H:i:s.u") . PHP_EOL;
或者也可以通过number_format处理:
$formattedTime = number_format($microtime, 6, '.', '');
修改后,无论microtime(true)返回多少位小数,都会被统一格式化为6位小数,确保U.u格式可以正确解析。
内容的提问来源于stack exchange,提问作者Andreas Hinderberger
相关产品推荐
相关产品推荐

