PHP IntlDateFormatter错误的日期/时间转换

时间:2017-07-21 00:09:17

标签: php timezone php-7 date-formatting

我最近偶然发现了PHP v7.0.4的问题。在尝试格式化过去的某些日期时。

我在一个项目上工作,其中有一个名为"空日期",基本上是" 1800-01-01" (用来代替NULL值)。我使用GMT + 1,"欧洲/柏林"。

在处理它的过程中,并且涉及到日期本地化,IntlDateFormatter开始提出一些问题,如果日期是< = 1893-04-01(4月初的傻瓜?),我就把它们追赶到例外。

您可以在下面看到一些有趣的例子。有人可以确认他们在他们的系统上遇到同样的问题吗?它应该可以重现:

$formatter = new \IntlDateFormatter('en_US', \IntlDateFormatter::MEDIUM, \IntlDateFormatter::LONG);
echo $formatter->format(new \DateTime("1893-04-01 00:00:00")) . '<br />';
echo $formatter->format(new \DateTime("1893-04-02 00:00:00")) . '<br />';

应返回:

"Mar 31, 1893, 11:53:28 PM GMT+0:53:28" and 
"Apr 2, 1893, 12:00:00 AM GMT+1"

或者更明显的行为&#34;改变&#34;:

echo $formatter->format(new \DateTime("1893-04-01 00:06:31")) . '<br />';
echo $formatter->format(new \DateTime("1893-04-01 00:06:32")) . '<br />';

应返回:

"Mar 31, 1893, 11:59:59 PM GMT+0:53:28" and
"Apr 1, 1893, 12:06:32 AM GMT+1"

我认为它与时区的历史变化有关(类似这样:https://github.com/eggert/tz/blob/2017b/asia#L891,虽然这是关于亚洲的,我使用GMT + 1)。

如果我们假设我真的需要使用这个日期,01.01.1800 - 任何人都会看到任何&#34;正常&#34;解决这个&#34;问题&#34;?

1 个答案:

答案 0 :(得分:1)

你是对的,它与historical change of the timezone有关。欧洲/柏林的格林尼治标准时间偏差为+0:53:28,直到1893年4月,它才会达到+1。

因此,它的第一个GMT + 1是:

  • 1893年4月1日,格林威治标准时间上午12:06:32 + 1

之前的第二个是:

  • 1893年3月31日,格林威治标准时间11:59:59 GM:00:53:28。

基本上这意味着1893年4月1日00:00:00到00:06:31不存在。

避免这种混乱的常见方法是仅在UTC中工作并处理时区转换仅用于显示。例如:

date_default_timezone_set('UTC');

$formatter = new \IntlDateFormatter(
    'en_US',
    \IntlDateFormatter::MEDIUM,
    \IntlDateFormatter::LONG,
    'Europe/Berlin'
);
echo $formatter->format(new \DateTime("1800-01-01 00:00:00")) , "\n";
echo $formatter->format(new \DateTime("1893-03-31 23:06:31")) , "\n";
echo $formatter->format(new \DateTime("1893-03-31 23:06:32")) , "\n";
echo $formatter->format(new \DateTime("1893-04-01 00:00:00")) , "\n";

输出:

Jan 1, 1800, 12:53:28 AM GMT+0:53:28
Mar 31, 1893, 11:59:59 PM GMT+0:53:28
Apr 1, 1893, 12:06:32 AM GMT+1
Apr 1, 1893, 1:00:00 AM GMT+1

如果你更愿意,你也可以强迫IntlDateFormatter使用GMT + 1而不是你的时区:

$formatter = new \IntlDateFormatter(
    'en_US',
    \IntlDateFormatter::MEDIUM,
    \IntlDateFormatter::LONG,
    'GMT+01:00'
);