9

我需要将 Date 对象转换为 TimeWithZone 对象,该对象表示给定时区中那一天的开始。

以下方法有效,但似乎过于复杂,因为它需要我将日期转换为字符串:

?> 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

我有没有更好的方法?

编辑:人们建议以下变化:

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

如您所见,这不是等效的转换,因为它是在美国东部标准时间 2 月 16 日开始时离开我的,而不是美国东部标准时间 2 月 17 日开始。

4

5 回答 5

10

我迟到了,但这仍然是一个很好的问题。自 OP 以来就引入了ActiveSupport in_time_zone,但它完全符合您的要求,无需解析字符串(慢)或设置 Time.zone(有风险):

>> 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

当然,如果您想以 UTC 表示一天的开始,您可以这样做:

>> date.in_time_zone('Eastern Time (US & Canada)').utc
=> 2010-02-17 05:00:00 UTC
于 2013-11-02T10:07:35.743 回答
4

如果您已Time.zone在 Rails 中设置,则可以调用Date#at_beginning_of_day(参见http://api.rubyonrails.org/classes/Date.html#method-i-at_beginning_of_day)。与此对比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
于 2012-05-31T21:04:58.757 回答
2

我强烈建议不要使用任何将日期转换为时间的解决方案,to_datetime或者to_time因为这些方法不知道该区域,并且in_time_zone正如一些答案所暗示的那样,根据结果进行修正不会追溯修复错误。此外,不要尝试使用 UTC 偏移量构建自己的夏令时数学。你一定会弄错,而且你做的工作是不必要的。

使用内置此逻辑的 TimeZone 本身。

给定一个区域和一个日期,您可以获得一天开始的 TimeWithZone,如下所示:

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

如果您想要一天中的特定时间而不是开始,您可以将小时、分钟和秒作为第 4、第 5 和第 6 个参数传递给#local.

如果zone实际上是您系统的本地时区 ( Time.zone),那么 ActiveSupport 会让您将上述内容缩短为:

time = date.to_time_in_current_zone

以上所有都正确处理夏令时。让我们通过两次查看 UTC 偏移量来验证这一点,一次在 DST 之外,一次在 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
于 2013-02-12T18:03:15.557 回答
0

像这样的东西对你有用吗?

'2010-04-01'.to_time.in_time_zone('Eastern Time (US & Canada)').beginning_of_day
于 2010-03-25T21:29:23.737 回答
0

减去 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 }

使用 ActiveSupport::TimeZone[tz] 不会考虑夏令时。

Time.zone.class.all.map(&:name).map { |tz| o = d.to_datetime.in_time_zone(tz).utc_offset - ActiveSupport::TimeZone[tz].utc_offset }
于 2011-05-19T06:14:35.333 回答