具有昏迷分离区域的微秒损失

时间:2018-02-26 15:35:44

标签: php datetime

当有人使用带有昏迷的本地作为小数分隔符时,有人会解释为什么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静态方法的解决方案。

谢谢,

2 个答案:

答案 0 :(得分:2)

它与区域设置十进制格式有关。 fr_FR,。尝试使用en_GBen_US.),它会显示微秒;尝试使用de_DEit_ITbg_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');