代码之家  ›  专栏  ›  技术社区  ›  userfuser

PHP IntlDateFormatter日期/时间转换错误

  •  2
  • userfuser  · 技术社区  · 9 年前

    我最近在PHP v7.0.4中遇到了一个问题。在过去尝试格式化一些日期时。

    我在做一个项目,其中有一个叫做“空日期”的东西,基本上是“1800-01-01”(用来代替空值)。我用的是GMT+1“欧洲/柏林”。

    你可以在下面看到一些有趣的例子。有人能确认一下他们的系统上有同样的问题吗?应可通过以下方式复制:

    $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"
    

    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,有人会认为这个“问题”有什么“正常”的解决方法吗?

    1 回复  |  直到 9 年前
        1
  •  1
  •   user3942918    9 年前

    你说得对,这与 historical change of the timezone 。欧洲/柏林的格林威治标准时间偏移为+0:53:28,直到1893年4月它跳到一个完整的+1。

    • 1893年4月1日上午12:06:32 GMT+1

    之前的第二个例子是:

    基本上这意味着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

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