Javascript and Ruby don't use the same time format, hence the discrepancy. The one Javascript uses (RFC 1123) is obsolete and is read wrong by some (but not all!) Ruby date-time-parsing method implementations, which expects something like RFC 2822 or ISO 8601. The discrepancy is fixed by making Javascript output to ISO format.
The Why
ActiveSupport::TimeZone#parse
, which you are using, internally uses Time::parse
directly on the string to get the time and then puts it in the desired timezone.
In your case, your string was output by the default javascript method Date.prototype.toString
, which usually gives a RFC 1123 format (but varies by implementation), which is mostly obsolete to RFC2822 and ISO8601.
A note on the different time standards (RFC, RFC, RFC!)
RFC1123 allows representing timezones with the "GMT" string such as "GMT+0800", while RFC2822 obsoletes that string in favor of a uniform UTC representation "+0800", without saying "GMT"/"UT". ISO8601 is even more compact (eg 20130227T0914-0500
) and so doesn't allow saying "GMT" either.
Coming back to our Rubies
So, Time::parse
, which uses Time::zone_offset
, can't recognize that timezone information (confused in particular with "GMT"), and falls back to the system timezone.
Using standard time formats
So indeed, like Saurabh points out, it's a matter of how your client serializes the time into a string. What I'd suggest is to change your parsed string to use a standard format like RFC2822 (that resembles your format) or ISO8601. In that case, your time should be parsed correctly.
irb(main):049:0> Time.zone.parse('Wed Feb 27 2013 19:46:21 GMT+0800 (PHT)')
=> Thu, 28 Feb 2013 00:46:21 UTC +00:00
irb(main):050:0> Time.zone.parse('Wed Feb 27 2013 19:46:21 +0800 (PHT)')
=> Wed, 27 Feb 2013 11:46:21 UTC +00:00
In a quick test I just made, Javascript doesn't seem to be able to output RFC 2822 strings (without "GMT") easily. But don't get out your gsub
just yet, there's no guarantee there'll be a "GMT" or "UTC" in there forever. Fortunately, ISO seems to be simple to do. (If the format fits your fancy, that is ;o) )
> new Date();
Wed, 27 Feb 2013 13:22:20 GMT # bad
> (new Date()).toString();
'Wed Feb 27 2013 08:22:25 GMT-0500 (EST)' # bad
> (new Date()).toUTCString();
'Wed, 27 Feb 2013 13:22:31 GMT' # still bad :(
> (new Date()).toISOString();
'2013-02-27T13:22:57.310Z' # good
Can't touch this! (the Javascript client)
Alternatively, if altering the client is out of question or you're looking for a quick-and-dirty fix, you could use Date::_parse
instead, it which seems to figure out your offset correctly.
irb(main):052:0> d = Date._parse('Wed Feb 27 2013 19:46:21 +0800 (PHT)')
=> {:wday=>3, :zone=>"+0800", :hour=>19, :min=>46, :sec=>21, :year=>2013, :mon=>2, :mday=>27, :offset=>28800}
irb(main):053:0> Time.new(d[:year], d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:offset])
=> 2013-02-27 19:46:21 +0800
However, I'm not sure this method can be relied on in the long-term, since it uses an internal date parse function. Besides, it's probably a good idea to use standard time strings.
So remember kids, standards are your friends! Use them!