converting Date object to TimeWithZone converting Date object to TimeWithZone ruby ruby

converting Date object to TimeWithZone


I'm late to the party, but this is still a great question. ActiveSupport's in_time_zone was introduced since the O.P., but it does exactly what you want without parsing a string (slow) or setting Time.zone (risky):

>> date = Date.parse("2010-02-17")=> Wed, 17 Feb 2010>> date.in_time_zone('Eastern Time (US & Canada)')=> Wed, 17 Feb 2010 00:00:00 EST -05:00

Of course if you want the beginning of day expressed at utc, you can do this:

>> date.in_time_zone('Eastern Time (US & Canada)').utc=> 2010-02-17 05:00:00 UTC


If you have Time.zone set in Rails then you can call Date#at_beginning_of_day (see http://api.rubyonrails.org/classes/Date.html#method-i-at_beginning_of_day). Contrast this with Date#to_datetime:

Time.zone => #<ActiveSupport::TimeZone:0x10cf10858 @tzinfo=#<TZInfo::TimezoneProxy: Etc/UTC>, @utc_offset=nil, @current_period=nil, @name="UTC"> date = Date.today => Thu, 31 May 2012 date.to_datetime => Thu, 31 May 2012 00:00:00 +0000 date.at_beginning_of_day => Thu, 31 May 2012 00:00:00 UTC +00:00 Time.zone = 'America/Chicago' => "America/Chicago" date.to_datetime => Thu, 31 May 2012 00:00:00 +0000 date.at_beginning_of_day => Thu, 31 May 2012 00:00:00 CDT -05:00


I strongly recommend against any solution that converts the date to a time using to_datetime or to_time because those methods are unaware of the zone, and tacking in_time_zone onto the result, as some answers suggest, won't retroactively fix the mistake. Also, don't try to build your own daylight saving time math using UTC offsets. You're bound to get it wrong, and you're doing work unnecessarily.

Use the TimeZone itself which has this logic built in.

Given a zone and a date, you can get a TimeWithZone for the beginning of the day like this:

time = zone.local(date.year, date.month, date.day)

If you want a specific time of day other than the beginning, you can pass the hour, minute, and second as the 4th, 5th, and 6th arguments to #local.

If zone is actually your system's local time zone (Time.zone), then ActiveSupport will let you shorten the above to this:

time = date.to_time_in_current_zone

All of the above handle daylight saving time correctly. Let's verify that by looking at the UTC offsets for two times, one that's outside DST and one that's within DST:

irb(main):009:0> zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']=> (GMT-05:00) Eastern Time (US & Canada)irb(main):010:0> t1 = zone.local(2013, 1, 1)=> Tue, 01 Jan 2013 00:00:00 EST -05:00irb(main):011:0> t2 = zone.local(2013, 5, 1)=> Wed, 01 May 2013 00:00:00 EDT -04:00irb(main):012:0> t1.utc_offset=> -18000irb(main):013:0> t2.utc_offset=> -14400