2

In my local machine, I am using RVM

>> ruby -v
=> ruby 1.9.3p194 (2012-04-20 revision 35410) [i686-linux]

# in the terminal
>> date
=> Wed Feb 27 20:00:17 PHT 2013

In our staging server, we are using rbenv

>> ruby -v
=> ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]

# in the terminal
>> date
=> Wed Feb 27 12:00:22 UTC 2013

In my local machine, I am parsing a date string that came from an ajax call

>> Time.zone
=> (GMT+00:00) UTC
>> Time.zone.parse('Wed Feb 27 2013 19:46:21 GMT+0800 (PHT)')
=> Wed, 27 Feb 2013 19:46:21 UTC +00:00

In our staging server, I get a different result

>> Time.zone
=> (GMT+00:00) UTC
>> Time.zone.parse('Wed Feb 27 2013 19:46:21 GMT+0800 (PHT)')
=> Wed, 27 Feb 2013 11:46:21 UTC +00:00

Any ideas how I can make the parse result on the staging server recognize the timezone?

jvnill
  • 29,479
  • 4
  • 83
  • 86

1 Answers1

4

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!

Community
  • 1
  • 1
Jonathan Allard
  • 18,429
  • 11
  • 54
  • 75