Ruby: Time.parse() Incorrectly Returning Alaskan Timezone

340 Views Asked by At

In my app, I am using

> Time.parse('12:30 pm MDT').utc
=> 2015-06-08 18:30:00 UTC
> Time.parse('12:30 pm EDT').utc
=> 2015-06-08 16:30:00 UTC
> Time.parse('12:30 pm CDT').utc
=> 2015-06-08 17:30:00 UTC
> Time.parse('12:30 pm PDT').utc
=> 2015-06-08 19:30:00 UTC
> Time.parse('12:30 pm MST').utc
=> 2015-06-08 19:30:00 UTC

Which all works just fine, but as soon as I start asking for hawaii or alaskan timezones, it returns an incorrect result:

> Time.parse('12:30 pm HST').utc
=> 2015-06-08 12:30:00 UTC
> Time.parse('12:30 pm HAST').utc
=> 2015-06-08 12:30:00 UTC
> Time.parse('12:30 pm AKDT').utc
=> 2015-06-08 12:30:00 UTC
> Time.parse('12:30 pm AKST').utc
=> 2015-06-08 12:30:00 UTC

Even this does not work:

> Time.parse('12:30 pm -800').utc
=> 2015-06-08 12:30:00 UTC

Does anyone have any idea why this is happening? And perhaps more importantly, does anyone have any advice about how to parse a time that is -800 or -900?

1

There are 1 best solutions below

0
On BEST ANSWER

The documentation of Time.parse contains (emphasis mine):

Since there are numerous conflicts among locally defined time zone abbreviations all over the world, this method is not intended to understand all of them. For example, the abbreviation “CST” is used variously as:

-06:00 in America/Chicago,
-05:00 in America/Havana,
+08:00 in Asia/Harbin,
+09:30 in Australia/Darwin,
+10:30 in Australia/Adelaide,
etc.

Based on this fact, this method only understands the time zone abbreviations described in RFC 822 and the system time zone, in the order named. (i.e. a definition in RFC 822 overrides the system time zone definition.) The system time zone is taken from Time.local(year, 1, 1).zone and Time.local(year, 7, 1).zone. If the extracted time zone abbreviation does not match any of them, it is ignored and the given time is regarded as a local time.

The following is from the syntax description in RFC 822 (5.1):

 zone        =  "UT"  / "GMT"                ; Universal Time
                                             ; North American : UT
             /  "EST" / "EDT"                ;  Eastern:  - 5/ - 4
             /  "CST" / "CDT"                ;  Central:  - 6/ - 5
             /  "MST" / "MDT"                ;  Mountain: - 7/ - 6
             /  "PST" / "PDT"                ;  Pacific:  - 8/ - 7
             /  1ALPHA                       ; Military: Z = UT;
                                             ;  A:-1; (J not used)
                                             ;  M:-12; N:+1; Y:+12
             / ( ("+" / "-") 4DIGIT )        ; Local differential
                                             ;  hours+min. (HHMM)

As you can see your timezone names aren't mentioned. You have to write -0800 and -0900 as the leading zero is required (to match the 4DIGIT part). If you want or have to keep the names, the more sophisticated DateTime class can be used.

Time.parse('12:30 pm -0800').utc # => 2015-06-08 20:30:00 UTC
DateTime.parse('12:30 pm AKDT').to_time.utc # => 2015-06-08 20:30:00 UTC