I have a problem to get UTC offset information out of PHP DateTimeZone and the underlying database. I'm get close for every DT/ST pair, but the time-zone with commonly one hour less (DT) isn't.
For example (source):
Eastern Daylight Time (EDT), when observing daylight saving time (spring/summer) is 4 hours behind Coordinated Universal Time (UTC−04:00).
Eastern Standard Time (EST) when observing standard time (autumn/winter) are 5 hours behind Coordinated Universal Time (UTC−05:00).
So far I obtain the UTC offset (in DateTimeZone::getOffset
it's said against GMT but I assume this is the same) as in the following code:
$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));
}
Exemplary output (full example, I use PHP 5.6.1RC1):
EDT (EDT) -0500
EST (EST) -0500
These two timezones are actually exemplary, I'd like to do that with others as well, however I don't want to hardcode the offsets but instead want to figure this out with PHP's DateTimeZone.
I might run into a bug here when I see the output across multiple PHP versions, looks like that HHVM does not have this issue by transposing it:
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
Is there a cross-PHP version compatible way? Not fiddling that deep with DateTimeZone
normally and so far I had the impression it would work well.
PHP uses the standard IANA tz database. You can find a list of supported time zones either on Wikipedia, or in the PHP documentation.
In particular, you will find that values like "EST"
are there for backwards compatibility only. You can see that in this page of the docs, there is a large red warning about not using time zones of that format. And while "EST"
is in the list of deprecated zones, "EDT"
is not.
In general, time zone abbreviations make poor identifiers because there are too many ambiguities. Consider this list of abbreviations, which has two different interpretations of EDT, 5 different interpretations of CST, and many other conflicts.
Also consider that a full identifier like "America/New_York"
is accurately representing both EST and EDT, and has all of the knowledge of when to transition between them - including historical differences.
In the code you provided, you are asking PHP for the current offset for EST and EDT separately. That doesn't make sense, since EDT is only in effect for part of the year, and EST and EDT can't be in effect at the same time in the same location. Instead, use the "America/New_York"
offset, and provide a specific time to get the offset at that time.
If you just want the standard and daylight offsets for each zone, you can test midnight on January 1st and July 1st of the current year. Whichever is lower is the standard offset. If they are the same, then (usually) the time zone doesn't use DST.
Not all time-zone which PHP's DateTimeZone accepts as string in the ctor's $timezone
parameter does actually have a stable UTC-offset. Technically speaking, those two EDT and EST, aren't real time-zones, the time-zone is Eastern Time Zone (ET) which is US/Eastern or America/New_York in the tz database and that is the datasource PHP's DateTimeZone operates on.
+------------------+--------------------+-----------------------------------------+
| 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) |
+------------------+--------------------+-----------------------------------------+
So especially those two EDT and EST in my question do not work well because they represent standard and daylight saving time separated, while PHP's DateTimeZone does represent both. Therefore the UTC offset is ambiguous. The PHP manual documents that those are accepted for backward-compatibility reasons only and they should not be used with the DateTimeZone class. A user-note on the page says it well:
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:
$dateObject = date_create("2013-06-30 07:00:00-0500");
This is sort of also what the specification I work with (4.3. Obsolete Date and Time; RFC2822 p. 32) is saying, that using those zones is obsolete. I just hoped I could have spared me the creation of a time-zone to UTC-offset map:
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
But it's not such a large list.