Ruby on rails 在Rails 3中,如何解析ISO8601日期字符串以获取TimeWithZone实例?
这是我的解决办法。有更紧凑的吗Ruby on rails 在Rails 3中,如何解析ISO8601日期字符串以获取TimeWithZone实例?,ruby-on-rails,date,timezone,iso8601,Ruby On Rails,Date,Timezone,Iso8601,这是我的解决办法。有更紧凑的吗 > 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
> 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
查看ActiveSupport::TimeWithZone
。简短回答:使用Time.parse(Time\u字符串)。在\u时区中
:
[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
不幸的是,这是不可能的,至少在没有变得更聪明的情况下是不可能的 要理解为什么必须区分时区和UTC偏移:
- 时区是指,并且可以选择具有
- A
下面是您的一个工作示例,您使用的是2001年3月30日星期五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
我们有美国/纽约
但是看看如果我们跳到夏季会发生什么,比方说,
2001年6月30日19:00:00
。来自客户端的时间\u的偏移分量现在将是-04:00
,这是纽约的夏时制偏移(EDT)
免责声明:下一步实际上不起作用,因为分子
将4/24
四舍五入到1/6
,您将得到一个不正确的时区偏移量
。因此,我调整了您的实现并使用了utc\u offset
> timezone_offset = time_from_client.to_datetime.utc_offset
=> -14400
> tz = ActiveSupport::TimeZone[timezone_offset]
=> (GMT-04:00) Atlantic Time (Canada)
现在可以看到问题了,我们得到的不是美国/纽约
而是大西洋时间(加拿大)
。后者是标准偏移量-04:00
的区域名称之一,因为只能使用标准utc_偏移量
查找,并且不知道日光
如果你遵循这一点得出结论,你最终会得到以下反直觉的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字符串的位置信息
顺便说一句,如果您采用这种方法,我建议使用Node.js库,它可以使用分区几何图形进行位置到分区的查找。不幸的是,这不是答案。我希望TimeWithZone实例所在的时区已包含在我从客户端获取的iso8601字符串中。当客户端作为另一个参数通过时区时,您的解决方案将起作用。请注意,在第一次解析时,您已经丢失了时区信息。谢谢,这是一个很好的答案!它应该是被接受的,伊姆霍。
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]