不幸的是这是不可能的,至少没有得到聪明得多。
要理解为什么你必须做出时区和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
,你会得到的1
不正确的timezone_offset
。因此,我调整了你的实现并使用了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
认为这是六月,所以调整到大西洋夏令偏移, -03:00
。
值得一提的是,甚至没有,如果你能解释日光,并获得标准偏移传递给ActiveSupport::TimeZone[]
,你仍然没有正确的区域,因为偏移区域映射ISN”一对一。
由于这里证明:
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库,它可以使用区域几何做区域查找的位置。
不幸的是,这不是答案。我希望TimeWithZone实例在IS中的时区已经包含在我从客户端获得的iso8601字符串中。当客户端将时区作为另一个参数传递时,您的解决方案将工作。请注意,在第一次解析时,您已经丢失了时区信息。 – 2013-03-28 04:45:04