Reputation: 3550
I have a String "3:30 PM 2014-03-15 Eastern Time (US & Canada)"
which I want to convert to a DateTime and store in my database.
This is pretty simple:
str = "3:30 PM 2014-03-15 Eastern Time (US & Canada)"
event.starts_at = DateTime.strptime(str, "%l:%M %p %Y-%m-%d %Z")
That creates a DateTime with the correct time zone. However, if I save the event to the database and then read it back out like so:
e.starts_at.in_time_zone("Eastern Time (US & Canada)")
.strftime("%l:%M %p") => #outputs 4:30 PM, when I want it to say 3:30 PM
The output is giving the wrong time (seems to be because it is adjusting for DST)! What can I do to fix this issue?
Upvotes: 4
Views: 1332
Reputation: 241555
DateTime.strptime
belongs to Ruby, while time zone identifiers like "Eastern Time (US & Canada)" are only provided by Rails via ActiveSupport::TimeZone.
In simple terms, DateTime
doesn't understand that time zone at all. You can find in the docs for DateTime
that the %z
and %Z
tokens are defined as follows:
Time zone:
%z - Time zone as hour and minute offset from UTC (e.g. +0900)
%:z - hour and minute offset from UTC with a colon (e.g. +09:00)
%::z - hour, minute and second offset from UTC (e.g. +09:00:00)
%:::z - hour, minute and second offset from UTC
(e.g. +09, +09:30, +09:30:30)
%Z - Time zone abbreviation name or something similar information.
The %z
definition makes sense, but the %Z
definition is laughable. It doesn't really say what is allowed or expected. Perhaps it is looking for an abbreviation like "EST" or "EDT", or perhaps it will allow some keywords like "Eastern". I'm really not sure, but I don't think it's likely that it's fully aware of Rails's idea of time zones (which are also laughable - see the very bottom of the timezone tag wiki).
Logically, what's happening in your code sample is that the value is being parsed in Eastern Standard Time - even though Eastern Daylight Time is in effect for the time you're passing. Just a guess, but something in the parser is probably picking up "eastern" and assuming EST. It's then saved in your database incorrectly with a -5 offset. When Rails loads it back and processes it with the general "Eastern Time (US & Canada)" time zone, it is aware of the fact that EDT is in effect, so it loads it with the correct -4 offset. The difference in offsets is why you see the result an hour off.
Suggestion #1 - Give up on Rails time zone identifiers. Use the Ruby TZInfo gem instead, which gives you normal IANA time zone ids like America/New_York
.
Suggestion #2 - If you must use Rails time zones, then use them in conjunction with Time.zone.parse
from Rails, instead of DateTime.strptime
.
(I'm not particularly fluent in Ruby or I would provide you an example. Perhaps someone can edit my response to provide one, or provide one in an answer of their own.)
Upvotes: 3