I need to convert a bunch of dates in a MySQL database from Pacific time (America/Los_Angeles) to UTC. I found a great SO answer on how to do this.
During my tests and preparation, I'm finding that I'm getting the same time conversions when using any of the following time zone names:
- America/Los_Angeles
- US/Pacific
- PST8PDT
So my questions are the following:
- Are these all just aliases to the same thing? Or are there actual differences between them at some point in time?
- If I want to provide a list of timezones to users on a website, would it be better to give them selections from开发者_如何学Go the
America
group of names, or theUS
group of names?
US/Pacific and PST8PDT both belong to the "other" timezones, which come with this warning:
Please do not use any of the timezones listed here (besides UTC), they only exist for backward compatible reasons.
They should all refer to the same timezone, compare:
http://www.travelmath.com/time-zone/PST8PDT
http://www.travelmath.com/time-zone/US/Pacific
http://www.travelmath.com/time-zone/America/Los_Angeles
As such, you should use America/Los_Angeles, which incidentally should also be a pretty "natural" and easy thing to select for users.
I ran into an issue with the parallel US/Eastern
, Americas/New_York
, and EST5EDT
. Here is what I discovered.
For dates after the Uniform Time Act of 1966 went into effect in 1967, these timezones are all identical. Also the US enforced standard DST rules during the World Wars, so they are all identical 1918-1919 and 1942-1945.
For any date before 1918, between 1920 and 1941 inclusive, and between 1946 and 1966 inclusive, EST5EDT
will always be identical to EST
. PST8PDT
will always be identical to PST.
Prior to 1967, Americas/New_York
will provide the time as observed in New York City. So Daylight Savings Time will follow the rules in place by the NYC municipal or NY state government. Any date before 1883 Nov 18 12:03:58 will be in local mean time with an offset of -4:56:02 from UTC. For Americas/Los_Angeles
any time before 1883 Nov 18 12:07:02 will be local mean time with an offset of -7:52:58 from UTC
. Between 1883 and 1967, Los Angeles follows the LA and California Daylight Savings rules.
Here is a fragment of Ruby showing the difference:
# In PST8PDT 1966 has no DST, but 1967 does.
ENV['TZ']='PST8PDT'
[Time.mktime(1966,6,2),Time.mktime(1967, 6, 2)]
=> [1966-06-02 00:00:00 -0800, 1967-06-02 00:00:00 -0700]
# In America/Los_Angeles both dates are in DST.
ENV['TZ']='America/Los_Angeles'
[Time.mktime(1966,6,2),Time.mktime(1967, 6, 2)]
=> [1966-06-02 00:00:00 -0700, 1967-06-02 00:00:00 -0700]
If you install the tzinfo gem for ruby you can see the difference between PST8PDT
and Americas/Los_Angeles
for historic dates:
require 'tzinfo'
# Here an old date will use modern timezone rules.
Time.new(1867, 6, 2, 0, 0, 0, TZInfo::Timezone.get("PST8PDT"))
=> 1867-06-02 00:00:00 -0800
# Here an old date predates timezones, so local time is used.
Time.new(1867, 6, 2, 0, 0, 0, TZInfo::Timezone.get("America/Los_Angeles"))
=> 1867-06-02 00:00:00 -0752
Odd things can happen if you have multiple systems where one assumes PST8PDT
and the other assumes Americas/Los_Angeles
, especially when a system is storing DATE
fields as DATETIME
fields with the hours/minutes/seconds set to midnight. Data might look fine for anything recent. But a birthdate for example, from the summer of 1966 might get moved an hour, then truncated so it appears to be on the prior day.
And just for extra fun if you are dealing with old dates in Alaska, you need to remember that Alaska was Purchased from Russia. Dates before 1867 Oct 18 are on the other side of the international date line and use the Julian, not Gregorian Calendar. So Juneau, for example, went from 6 Oct 1867 (Julian) +15:02:19 to 18-Oct-1867 (Gregorian) -8:57:41. (The TZInfo library doesn't handle the Gregorian to Julian change.)
Time.new(1867, 10, 18, 0, 0, 0, TZInfo::Timezone.get("America/Juneau"))
=> 1867-10-18 00:00:00 +1502
Time.new(1867, 10, 19, 0, 0, 0, TZInfo::Timezone.get("America/Juneau"))
#error message
TZInfo::AmbiguousTime (1867-10-19 00:00:00 is an ambiguous local time.)
Time.new(1867, 10, 20, 0, 0, 0, TZInfo::Timezone.get("America/Juneau"))
=> 1867-10-20 00:00:00 -0857
Time.new(1867, 10, 18, 0, 0, 0, TZInfo::Timezone.get("America/Juneau")).to_datetime.julian
=> 1867-10-06 00:00:00 +1502
US/Pacific
is a "link" to America/Los_Angeles
in the IANA database (see wikipedia). On Linux systems I've seen, the former is a hard linked file to the latter; on OS X it might be a copy. If you run a checksum (e.g. md5 or sha1) on the entries in /usr/share/zoneinfo/
the 2 should match.
However, PST8PDT
may be different - I haven't figured out exactly how. This bug report indicates that it doesn't track the history of daylight-saving changes, i.e. that it just retroactively applies the current DST rules to the past; but that doesn't seem to be the case in this ruby example. If it were retroactively applying the current rules, both would be -0700
:
> ENV['TZ']='PST8PDT'
> [Time.mktime(2006, 4, 2, 1, 59, 59), Time.mktime(2006, 4, 2, 2)]
=> [2006-04-02 01:59:59 -0800, 2006-04-02 03:00:00 -0700]
On this message there's a quote from the original database maintainer. The message author explains that the legacy zones including PST8PDT
used to have obsolete info, but now are "less incorrect" whatever that means.
To sum up, don't use PST8PDT
, but it should be safe to use either US/Pacific
or America/Los_Angeles
.
精彩评论