不幸的是,这是不可能的,至少在没有变得更聪明的情况下是不可能的。
要了解为什么必须区分时区和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
。因此,我调整了您的实现并使用了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 库,它可以使用区域几何来执行区域查找。