jpw
jpw

Reputation: 19247

In ruby, how create UTC time for an arbitrary future time in an arbitrary timezone, accounting for DST (when applicable)?

In a scheduling method, I need to take a (local_date, local_time, and local_time_zone), and return the corresponding utc time accounting for whether Daylight Saving time is in effect on that date.

I do not want to change Time.zone since while threadsafe, it has the entirely unexpected result of persisting across multiple requests - a Bad Thing.

The following (0800 Pacific time) does NOT work because they return the same time in UTC (16:00) even though the first day (Oct 1) IS in daylight saving time and the second day (Dec 1) is NOT in daylight savings time, so the UTC should be different

Time.new(2012, 10, 1, 8, 0, 0, ActiveSupport::TimeZone['Pacific Time (US & Canada)'].utc_offset).utc
# 2012-10-01 16:00:00 UTC <<<< should be 15:00

Time.new(2012, 12, 1, 8, 0, 0, ActiveSupport::TimeZone['Pacific Time (US & Canada)'].utc_offset).utc
# 2012-12-01 16:00:00 UTC 

I had hoped that the .utc method would take into account whether the daylight saving is in effect, but it doesn't.

I'm not sure if I should be using a Time object, a DateTime object, and TimeWith Zone, etc.

===

Note: There IS a way to do it using the Chronic gem (below). But I would like to use the built-in Ruby Date and Time methods to get the same (eg, correct) result:

Chronic.time_class =ActiveSupport::TimeZone["Pacific Time (US & Canada)"]
Chronic.parse("10/1/2012 0800").utc
# 2012-10-01 15:00:00 UTC 
Chronic.parse("12/1/2012 0800").utc
# 2012-12-01 16:00:00 UTC 

Upvotes: 2

Views: 1789

Answers (2)

jpw
jpw

Reputation: 19247

Found it on another SO thread: the trick is to put the time (and zone) into a format usable by Time.parse:

Time.parse("2012-10-1 8:00:00 Pacific Time (US & Canada)").utc
# 2012-10-01 15:00:00 UTC 

Time.parse("2012-12-1 8:00:00 Pacific Time (US & Canada)").utc
# 2012-12-01 16:00:00 UTC

ANOTHER METHOD (probably better):

ActiveSupport::TimeZone["Pacific Time (US & Canada)"].parse("2012-12-1 8am").utc

After some playing around it looks like we were right to be wary of changing Time.zone simply to create a time in a certain zone -- setting Time.zone can 'stick' over multiple requests (in the same thread). So if you have two different windows open to a rails app, and are viewing two different accounts, setting Time.zone for the account in one window can actually change the Time.zone in the other window for the other account.

Upvotes: 1

Averenix
Averenix

Reputation: 408

I recently went through something similar and found Time.zone.local to work fine taking daylight savings into account. I'm not sure about US daylight savings, but here in Australia daylight savings kick in on the 6th October 2013.

The following code seems to work fine for me:

1.9.3-p194 :009 > Time.zone = 'Sydney'
 => "Sydney" 
1.9.3-p194 :010 > Time.zone.local(2013, 10, 1, 0, 0, 0).utc
 => 2013-09-30 14:00:00 UTC 
1.9.3-p194 :011 > Time.zone.local(2013, 10, 10, 0, 0, 0).utc
 => 2013-10-09 13:00:00 UTC 

Are you sure your dates / time zones are correct? Seems that Pacific Time experiences daylight savings in November according to this page: http://www.timeanddate.com/worldclock/timezone.html?n=137

Upvotes: 0

Related Questions