关于php:标准和日光时间的DateTimeZone和UTC偏移量

DateTimeZone and UTC offset for Standard and Daylight Times

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

例如(来源):

东部夏令时(EDT),当观察夏令时(春/夏)时,比世界协调时间(UTC?04:00)落后4小时。

东部标准时间(EST),当观察标准时间(秋/冬)时,比协调世界时(落后标准时间05:00)落后5小时。

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

1
2
3
4
5
6
7
8
9
10
$zones = ['EDT', 'EST'];

foreach ($zones as $zone) {
    // get offset
    $timezone = new DateTimeZone($zone);
    $offset = $timezone->getOffset(new DateTime(null, $timezone));

    printf("%s (%s) %s
"
, $zone, $timezone->getName(), format_offset($offset));
}

示例输出(完整示例,我使用PHP 5.6.1RC1):

1
2
EDT (EDT) -0500
EST (EST) -0500

这两个时区实际上是示范性的,我也想与其他时区一起做,但是我不想对偏移进行硬编码,而是希望用PHP的DateTimeZone来解决这个问题。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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数据库。您可以在Wikipedia或PHP文档中找到支持的时区列表。

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

通常,时区缩写会使标识符变差,因为模糊性太多。考虑这个缩写列表,它有两种不同的EDT解释,5种不同的CST解释,以及许多其他冲突。

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

在您提供的代码中,您将分别向PHP询问EST和EDT的当前偏移量。这没有意义,因为EDT仅在一年中的部分时间生效,并且EST和EDT不能在同一位置同时生效。相反,使用"America/New_York"偏移量,并提供特定时间来获取此时的偏移量。

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


并非PHP的DateTimeZone在ctor的$timezone参数中作为字符串接受的所有时区实际上都具有稳定的UTC偏移量。从技术上讲,那两个EDT和EST,不是真正的时区,时区是东部时区(ET),它是美国/东部或美国/纽约的tz数据库,也就是PHP的DateTimeZone运行的数据源。

1
2
3
4
5
6
7
8
+------------------+--------------------+-----------------------------------------+
| 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) |
+------------------+--------------------+-----------------------------------------+

所以特别是我的问题中的那两个EDT和EST不能很好地工作,因为它们代表标准和夏令时分开,而PHP的DateTimeZone确实代表两者。因此,UTC偏移是不明确的。 PHP手册记录了那些仅出于向后兼容性原因而被接受的文档,它们不应与DateTimeZone类一起使用。页面上的用户注释说得很好:

Don’t use 'EST', at least in PHP 5.3.3 it’s the same as 'EST5EDT' rather than being strictly standard time. The only reliable way I’ve found to interpret a time as standard time is to use a UTC-relative format such as:

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

这也是我使用的规范(4.3。过时的日期和时间; RFC2822第32页)所说的,使用这些区域已经过时了。我只是希望我可以免除我为UTC偏移地图创建一个时区:

1
2
3
4
5
6
7
8
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

但它不是一个如此大的清单。