这是我的解决方案。有一个更紧凑的吗?
> time_from_client = "2001-03-30T19:00:00-05:00"
=> "2001-03-30T19:00:00-05:00"
> time_from_client.to_datetime
=> Fri, 30 Mar 2001 19:00:00 -0500
> timezone_offset = time_from_client.to_datetime.offset.numerator
=> -5
> tz = ActiveSupport::TimeZone[timezone_offset]
=> (GMT-05:00) America/New_York
> tz.class
=> ActiveSupport::TimeZone
答案 0 :(得分:2)
不幸的是,这是不可能的,至少没有变得更聪明。
要理解为什么必须区分时区和 UTC偏移:
考虑从区域到偏移的映射:您还必须知道相关时间以及区域,以便决定是应用标准偏移还是日光偏移。
走另一条路要困难得多。再次只是偏移是不够的,因为我们不知道该偏移是指标准时间还是日光时间。但是这次我们有鸡/蛋问题:即使我们有时间,我们也需要知道区域,以便查看该时间是标准时间还是白天时间。但是,我们没有这个区域。
这是你的一个有用的例子,你正在使用Fri, 30 Mar 2001 19:00:00
,这恰好是标准时间(EST),所以在第一次通过它看起来不错:
> time_from_client = "2001-03-30T19:00:00-05:00"
=> "2001-03-30T19:00:00-05:00"
> time_from_client.to_datetime
=> Fri, 30 Mar 2001 19:00:00 -0500
> timezone_offset = time_from_client.to_datetime.offset.numerator
=> -5
> tz = ActiveSupport::TimeZone[timezone_offset]
=> (GMT-05:00) America/New_York
我们有America/New_York
。
但是看看如果我们跳到夏令时会发生什么,让我们说,30 Jun 2001 19:00:00
。您time_from_client
的偏移量组件现在为-04:00
,这是纽约(EDT)的日光时间偏移量。
> time_from_client = "2001-03-30T19:00:00-4:00"
=> "2001-06-30T19:00:00-05:00"
> time_from_client.to_datetime
=> Fri, 30 Jun 2001 19:00:00 -0400
免责声明:下一步实际上不起作用,因为numerator
会将4/24
向下舍入到1/6
,并且您将timezone_offset
1
1}}。因此我调整了您的实现并使用了utc_offset
。
> timezone_offset = time_from_client.to_datetime.utc_offset
=> -14400
> tz = ActiveSupport::TimeZone[timezone_offset]
=> (GMT-04:00) Atlantic Time (Canada)
现在可以看到问题,而不是America/New_York
我们得到Atlantic Time (Canada)
。后者是标准偏移-04:00
的区域名称中的一个,因为implementation of ActiveSupport::TimeZone[]
只能使用标准utc_offset
找到,并且不知道日光。
如果您按照此结论得出结论,您最终会遇到以下违反直觉的parse
:
> tz.parse "2001-06-30T19:00:00-04:00"
=> Sat, 30 Jun 2001 20:00:00 ADT -03:00
我假设在这里发生的是TimeWithZone
看到这是6月,因此调整为大西洋日光偏移-03:00
。
值得注意的是,即使您可以考虑日光,并获得传递给ActiveSupport::TimeZone[]
的标准偏移,您仍然没有正确的区域,因为偏移区域映射不是一对一的。
如此处所示:
ActiveSupport::TimeZone.all.select { |z| z.utc_offset == -14400 }
=> [(GMT-04:00) Atlantic Time (Canada), (GMT-04:00) Georgetown, (GMT-04:00) La Paz, (GMT-04:00) Santiago]
这是我认为这是不可能的原因,除非您碰巧有原始ISO 8601字符串的位置信息。
顺便提一下,如果您采用这种方法,我建议使用tzwhere Node.js库,它可以使用区域几何体来区域查找位置。
答案 1 :(得分:1)
查看ActiveSupport::TimeWithZone
的{{3}}。简短回答:使用Time.parse(time_string).in_time_zone
:
[9] pry(main)> Time.parse("2001-03-30T19:00:00-05:00")
=> 2001-03-30 19:00:00 -0500
[10] pry(main)> Time.parse("2001-03-30T19:00:00-05:00").class
=> Time
[11] pry(main)> Time.parse("2001-03-30T19:00:00-05:00").in_time_zone
=> Sat, 31 Mar 2001 00:00:00 UTC +00:00
[12] pry(main)> Time.parse("2001-03-30T19:00:00-05:00").in_time_zone.class
=> ActiveSupport::TimeWithZone
如果你想在另一个时区:
[13] pry(main)> Time.parse("2001-03-30T19:00:00-05:00").in_time_zone("America/Los_Angeles")
=> Fri, 30 Mar 2001 16:00:00 PST -08:00