converting Date object to TimeWithZone

ぐ巨炮叔叔 提交于 2019-12-03 19:34:26

问题


I need to convert a Date object into a TimeWithZone object representing the beginning of that day in a given time zone.

The following approach works, but seems too convoluted as it requires me to convert the date to a string:

?> date = Date.parse("2010-02-17")
=> Wed, 17 Feb 2010
>> ActiveSupport::TimeZone['Eastern Time (US & Canada)'].parse(date.to_s)
=> Wed, 17 Feb 2010 00:00:00 EST -05:00
>> ActiveSupport::TimeZone['UTC'].parse(date.to_s)
=> Wed, 17 Feb 2010 00:00:00 UTC 00:00

Is there a better way I'm missing?

Edit: People are suggesting variations of:

?> date.to_datetime.in_time_zone('Eastern Time (US & Canada)').beginning_of_day
=> Tue, 16 Feb 2010 00:00:00 EST -05:00

As you can see, this isn't an equivalent conversion since it leaves me at the start of Feb. 16th EST, instead of the start of Feb. 17th EST.


回答1:


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



回答2:


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



回答3:


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:00
irb(main):011:0> t2 = zone.local(2013, 5, 1)
=> Wed, 01 May 2013 00:00:00 EDT -04:00
irb(main):012:0> t1.utc_offset
=> -18000
irb(main):013:0> t2.utc_offset
=> -14400



回答4:


Would something like this work for you?

'2010-04-01'.to_time.in_time_zone('Eastern Time (US & Canada)').beginning_of_day



回答5:


Subtract utc_offset:

d = Date.today
Time.zone.class.all.map(&:name).map { |tz| dt = d.to_datetime.in_time_zone(tz); dt -= dt.utc_offset }

Using ActiveSupport::TimeZone[tz] doesn't take daylight savings time into account.

Time.zone.class.all.map(&:name).map { |tz| o = d.to_datetime.in_time_zone(tz).utc_offset - ActiveSupport::TimeZone[tz].utc_offset }


来源:https://stackoverflow.com/questions/2518398/converting-date-object-to-timewithzone

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!