标准时间和夏令时的日期时区和UTC偏移量


DateTimeZone and UTC offset for Standard and Daylight Times

我在从PHP DateTimeZone和底层数据库中获取UTC偏移量信息时遇到问题。我已经接近了每对DT/ST,但通常少一小时(DT)的时区不是。

例如(来源):

东部夏令时美国东部时间),当观测夏令时(春季/夏季)时,比协调世界时(UTC−04:00)晚4小时。

当观测标准时间(秋季/冬季)比协调世界时(UTC−05:00)晚5小时时,东部标准时间(东部标准时间)。

到目前为止,我获得了UTC偏移量(在DateTimeZone::getOffset中,它是针对GMT的,但我认为这是相同的),如下代码所示:

$zones = ['EDT', 'EST'];
foreach ($zones as $zone) {
    // get offset
    $timezone = new DateTimeZone($zone);
    $offset = $timezone->getOffset(new DateTime(null, $timezone));
    printf("%s (%s) %s'n", $zone, $timezone->getName(), format_offset($offset));
}

示例性输出(完整的示例,我使用PHP 5.6.RC1):

EDT (EDT) -0500
EST (EST) -0500

这两个时区实际上是示例性的,我也想对其他时区也这样做,但我不想硬编码偏移量,而是想用PHP的DateTimeZone来解决这个问题。

当我看到多个PHP版本的输出时,我可能会遇到一个错误,看起来HHVM通过转换它没有这个问题:

Output for hhvm-3.2.0 - 3.3.0
EDT (America/New_York) -0400
EST (EST) -0500
Output for 5.5.10 - 5.6.2, php7@20140507 - 20141001
EDT (EDT) -0500
EST (EST) -0500
Output for 5.2.0 - 5.5.9
EDT (America/New_York) -0400
EST (America/New_York) -0400

有没有跨PHP版本兼容的方式?通常不会对DateTimeZone进行那么深入的处理,到目前为止,我的印象是它会很好地工作。

PHP使用标准的IANA tz数据库。您可以在维基百科或PHP文档中找到受支持时区的列表。

特别是,您会发现像"EST"这样的值仅用于向后兼容性。您可以看到,在文档的这一页中,有一个关于使用该格式时区的红色警告。虽然"EST"在不推荐使用的区域列表中,但"EDT"不在。

一般来说,时区缩写是不好的标识符,因为有太多的歧义。考虑一下这个缩写列表,它对EDT有两种不同的解释,对CST有五种不同的理解,以及许多其他冲突。

还要考虑像"America/New_York"这样的完整标识符准确地表示EST和EDT,并且具有何时在它们之间转换的所有知识,包括历史差异。

在您提供的代码中,您要求PHP分别为EST和EDT提供当前偏移量。这没有道理,因为美国东部时间只在一年中的一部分时间生效,而美国东部时间和美国东部时间不可能在同一地点同时生效。相反,使用"America/New_York"偏移量,并提供特定的时间来获得该时间的偏移量。

如果您只想要每个区域的标准偏移量和日光偏移量,可以在当年的1月1日和7月1日的午夜进行测试。以较低者为标准偏移。如果它们相同,则(通常)时区不使用夏令时。

并非PHP的DateTimeZone在ctor的$timezone参数中接受为字符串的所有时区实际上都有稳定的UTC偏移量。从技术上讲,这两个EDTEST不是实时时区,时区是东部时区ET),它是tz数据库中的美国/东部美洲/纽约,这是PHP的DateTimeZone操作的数据源。

+------------------+--------------------+-----------------------------------------+
| string           | getName()          | offsets                                 |
+------------------+--------------------+-----------------------------------------+
| America/New_York | (America/New_York) | -0500 / -0400 (2012-01-01 / 2012-06-30) |
| US/Eastern       | (US/Eastern)       | -0500 / -0400 (2012-01-01 / 2012-06-30) |
| EDT              | (EDT)              | -0500 / -0500 (2012-01-01 / 2012-06-30) |
| EST              | (EST)              | -0500 / -0500 (2012-01-01 / 2012-06-30) |
+------------------+--------------------+-----------------------------------------+

因此,特别是我的问题中的两个EDTEST工作不好,因为它们分别代表标准时间和夏令时,而PHP的DateTimeZone确实代表两者。因此,UTC偏移量不明确。PHP手册说明,这些仅出于向后兼容性的原因而被接受,不应与DateTimeZone类一起使用。页面上的用户说明说得很好:

不要使用"EST",至少在PHP 5.3.3中,它与"EST5EDT"相同,而不是严格的标准时间。我发现将时间解释为标准时间的唯一可靠方法是使用UTC相对格式,例如:

$dateObject = date_create("2013-06-30 07:00:00-0500");

这也是我使用的规范(4.3。过时的日期和时间;RFC2822第32页)说,使用这些区域是过时的。我只是希望我能省去创建一个时区到UTC偏移地图的麻烦:

EDT is semantically equivalent to -0400
EST is semantically equivalent to -0500
CDT is semantically equivalent to -0500
CST is semantically equivalent to -0600
MDT is semantically equivalent to -0600
MST is semantically equivalent to -0700
PDT is semantically equivalent to -0700
PST is semantically equivalent to -0800

但这并不是一个很大的清单。