5

这是我的解决方案。有没有更紧凑的?

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

2 回答 2

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:00time_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/241/6,你会得到一个不正确timezone_offset1。因此,我调整了您的实现并使用了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). 后者是标准 offset 的区域名称之一-04:00因为 的实现ActiveSupport::TimeZone[]只能使用标准 find 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[]偏移量,您仍然没有正确的区域,因为区域映射的偏移量不是一对一的。

如此处所示:

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 库,它可以使用区域几何来执行区域查找。

于 2013-06-17T17:21:07.853 回答
1

查看. _ _ ActiveSupport::TimeWithZone简短回答:使用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
于 2013-03-27T23:59:58.793 回答