当有人使用带有昏迷的本地作为小数分隔符时,有人会解释为什么PHP DateTime构造函数会忽略微秒吗?
$date = new \DateTime('2017-07-29T13:57:27.123456Z');
echo $date->format('Y-m-d H:i:s.u e');
echo "\n";
setlocale(LC_ALL, 'fr'); // or any locale with coma as decimal separator
$date = new \DateTime('2017-07-29T13:57:27.123456Z');
echo $date->format('Y-m-d H:i:s.u e');
输出:
2017-07-29 13:57:27.123456 Z
2017-07-29 13:57:27.000000 Z
听起来像是一个PHP错误。有解决办法吗?
重要说明:要重现,您需要安装并使用具有昏迷作为小数分隔符的区域设置。如果您运行setlocale(LC_ALL, 'fr')
但未安装fr语言环境,则setlocale
无效。
PS:我不能使用createFromFormat。因为我在构造函数中扩展了DateTime并需要它,所以我需要一个不使用DateTime静态方法的解决方案。
谢谢,
答案 0 :(得分:2)
它与区域设置十进制格式有关。 fr_FR
有,
。尝试使用en_GB
或en_US
(.
),它会显示微秒;尝试使用de_DE
,it_IT
或bg_BG
(也有,
),但它不会显示它们。
% cat en_GB/LC_NUMERIC
. # <--- decimal separator - microseconds
,
3;3
% cat en_US/LC_NUMERIC
. # <--- decimal separator - microseconds
,
3;3
% cat it_IT/LC_NUMERIC
, # <--- decimal separator - no microseconds
.
0;0
% cat de_DE/LC_NUMERIC
, # <--- decimal separator - no microseconds
-1
% cat fr_FR/LC_NUMERIC
, # <--- decimal separator - no microseconds
-1
% cat bg_BG/LC_NUMERIC
, # <--- decimal separator - no microseconds
3;3
因此解决方法是将您的小数点分隔符设置为法语区域设置的.
,这显然会破坏其他所有内容。
就像@FelippeDuarte在评论中所说,这似乎是一个已知的错误:PHP Bug #67127。你可以在那里阅读更多有关问题的信息。那里的人还在搞清楚:
我可以确认这个问题。罪魁祸首是在timelib_get_frac_nr() 其中使用strtod()[1],这是locale dependend。运用 相反,zend_strtod()会解决问题,但这样做会有所帮助 timelib取决于Zend引擎,当然不是 期望的。
答案 1 :(得分:0)
正如@FelippeDuarte指出的那样,它似乎是一个已知错误(https://bugs.php.net/bug.php?id=67127)并且似乎无法仅更改小数分隔符,应更改和恢复LC_NUMERIC
语言环境。支持点最广泛的区域设置是C
。
所以似乎没有更好的解决办法:
if (strpos((string) .1, '.') === false) {
$locale = setlocale(LC_NUMERIC, '0');
setlocale(LC_NUMERIC, 'C');
}
$date = new \DateTime('2017-07-29T13:57:27.123456Z');
if (isset($locale)) {
setlocale(LC_NUMERIC, $locale);
}
echo $date->format('Y-m-d H:i:s.u e');