PHP IntlDateFormatter 转换错误 date/time
PHP IntlDateFormatter wrong date/time conversion
我最近偶然发现了 PHP v7.0.4 的一个问题。尝试格式化过去的某些日期时。
我在一个项目中工作,其中有一个叫做 "empty date" 的东西,基本上是一个“1800-01-01”(用来代替 NULL 值)。我正在使用 GMT+1,"Europe/Berlin".
在处理它的过程中,并且涉及到日期本地化,IntlDateFormatter 开始出现一些问题,如果日期 <= 1893-04-01(四月初的傻事? ).
您可以在下面看到一些有趣的示例。有人可以确认他们在他们的系统上遇到了同样的问题吗?它应该可以重现:
$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 />';
哪个应该 return:
"Mar 31, 1893, 11:53:28 PM GMT+0:53:28" and
"Apr 2, 1893, 12:00:00 AM GMT+1"
或者更明显的行为"change":
echo $formatter->format(new \DateTime("1893-04-01 00:06:31")) . '<br />';
echo $formatter->format(new \DateTime("1893-04-01 00:06:32")) . '<br />';
哪个应该 return:
"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 - 有人会看到任何 "normal" 绕过这个 "problem" 的方法吗?
你是对的,它与historical change of the timezone有关。 Europe/Berlin 的 GMT 偏移量是 +0:53:28,直到 1893 年 4 月跳到完整的 +1。
因此它的第一个 GMT+1 是:
- 1893 年 4 月 1 日,12:06:32 上午 GMT+1
之前的第二个是:
- 1893 年 3 月 31 日,11:59:59 下午 GMT+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'
);
我最近偶然发现了 PHP v7.0.4 的一个问题。尝试格式化过去的某些日期时。
我在一个项目中工作,其中有一个叫做 "empty date" 的东西,基本上是一个“1800-01-01”(用来代替 NULL 值)。我正在使用 GMT+1,"Europe/Berlin".
在处理它的过程中,并且涉及到日期本地化,IntlDateFormatter 开始出现一些问题,如果日期 <= 1893-04-01(四月初的傻事? ).
您可以在下面看到一些有趣的示例。有人可以确认他们在他们的系统上遇到了同样的问题吗?它应该可以重现:
$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 />';
哪个应该 return:
"Mar 31, 1893, 11:53:28 PM GMT+0:53:28" and
"Apr 2, 1893, 12:00:00 AM GMT+1"
或者更明显的行为"change":
echo $formatter->format(new \DateTime("1893-04-01 00:06:31")) . '<br />';
echo $formatter->format(new \DateTime("1893-04-01 00:06:32")) . '<br />';
哪个应该 return:
"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 - 有人会看到任何 "normal" 绕过这个 "problem" 的方法吗?
你是对的,它与historical change of the timezone有关。 Europe/Berlin 的 GMT 偏移量是 +0:53:28,直到 1893 年 4 月跳到完整的 +1。
因此它的第一个 GMT+1 是:
- 1893 年 4 月 1 日,12:06:32 上午 GMT+1
之前的第二个是:
- 1893 年 3 月 31 日,11:59:59 下午 GMT+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'
);