ruby-on-rails - ruby 版本之间的时区解析差异

标签 ruby-on-rails ruby timezone

在我的本地计算机中,我使用 RVM

>> ruby -v
=> ruby 1.9.3p194 (2012-04-20 revision 35410) [i686-linux]

# in the terminal
>> date
=> Wed Feb 27 20:00:17 PHT 2013

在我们的临时服务器中,我们使用 rbenv

>> ruby -v
=> ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]

# in the terminal
>> date
=> Wed Feb 27 12:00:22 UTC 2013

在我的本地计算机中,我正在解析来自 ajax 调用的日期字符串

>> Time.zone
=> (GMT+00:00) UTC
>> Time.zone.parse('Wed Feb 27 2013 19:46:21 GMT+0800 (PHT)')
=> Wed, 27 Feb 2013 19:46:21 UTC +00:00

在我们的临时服务器中,我得到了不同的结果

>> Time.zone
=> (GMT+00:00) UTC
>> Time.zone.parse('Wed Feb 27 2013 19:46:21 GMT+0800 (PHT)')
=> Wed, 27 Feb 2013 11:46:21 UTC +00:00

有什么想法可以让临时服务器上的解析结果识别时区吗?

最佳答案

Javascript 和 Ruby 不使用相同的时间格式,因此存在差异。 Javascript 使用的一个 (RFC 1123) 已过时,并且被一些(但不是全部!)Ruby 日期时间解析方法实现读取错误,这些实现需要类似于 RFC 2822 或 ISO 8601 的内容。通过将 Javascript 输出设置为ISO 格式。

原因

您正在使用的

ActiveSupport::TimeZone#parse ,在内部直接在字符串上使用 Time::parse 来获取时间,然后将其放入所需的时区。

在您的情况下,您的字符串是由默认的 javascript 方法 Date.prototype.toString 输出的,该方法通常提供 RFC 1123 格式(但因实现而异),该格式大部分已过时为 RFC2822ISO8601

关于不同时间标准的说明(RFC、RFC、RFC!)

RFC1123 允许使用“GMT”字符串表示时区,例如“GMT+0800”,而 RFC2822 废​​弃该字符串,转而采用统一的 UTC 表示“+0800”,而不用说“GMT”/“UT”。 ISO8601 更加紧凑(例如 20130227T0914-0500),因此也不允许说“GMT”。

回到我们的 ruby

因此,使用 Time::zone_offsetTime::parse 无法识别该时区信息(特别是与“GMT”混淆),并回退到系统时区。

使用标准时间格式

确实,正如 Saurabh 指出的那样,问题在于客户端如何将时间序列化为字符串。我建议是将解析的字符串更改为使用标准格式,例如 RFC2822 (类似于您的格式)或 ISO8601 。在这种情况下,您的时间应该被正确解析。

irb(main):049:0> Time.zone.parse('Wed Feb 27 2013 19:46:21 GMT+0800 (PHT)')
=> Thu, 28 Feb 2013 00:46:21 UTC +00:00
irb(main):050:0> Time.zone.parse('Wed Feb 27 2013 19:46:21 +0800 (PHT)')
=> Wed, 27 Feb 2013 11:46:21 UTC +00:00

在我刚刚进行的快速测试中,Javascript 似乎无法轻松输出 RFC 2822 字符串(没有“GMT”)。但暂时不要拿出您的 gsub,不能保证那里永远会有“GMT”或“UTC”。幸运的是,ISO 似乎做起来很简单。 (如果格式符合您的喜好,那就是 ;o) )

> new Date();
Wed, 27 Feb 2013 13:22:20 GMT # bad
> (new Date()).toString();
'Wed Feb 27 2013 08:22:25 GMT-0500 (EST)' # bad
> (new Date()).toUTCString();
'Wed, 27 Feb 2013 13:22:31 GMT' # still bad :(
> (new Date()).toISOString();
'2013-02-27T13:22:57.310Z' # good

不能碰这个! (Javascript 客户端)

或者,如果更改客户端是不可能的,或者您正在寻找快速而肮脏的修复,您可以使用 Date::_parse 来代替,它似乎可以找出您的正确偏移。

irb(main):052:0> d = Date._parse('Wed Feb 27 2013 19:46:21 +0800 (PHT)')
=> {:wday=>3, :zone=>"+0800", :hour=>19, :min=>46, :sec=>21, :year=>2013, :mon=>2, :mday=>27, :offset=>28800}
irb(main):053:0> Time.new(d[:year], d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:offset])
=> 2013-02-27 19:46:21 +0800

但是,我不确定这个方法是否可以长期依赖,因为它使用内部日期解析函数。此外,使用标准时间字符串可能是个好主意。

所以记住 children ,标准是你的 friend !使用它们!

关于ruby-on-rails - ruby 版本之间的时区解析差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15111621/

相关文章:

ruby - 如果第一次没有输入,如何重新询问用户输入?

ruby - Haml + ActionMailer - Rails?

ruby-on-rails - Rspec 跳过 Controller 中的设计操作 - sign_in_and_redirect

html - Rails content_tag 帮助器用于简单的事情?

mysql - 如何使用 rails 在 mysql 数据库中查找浮点值

javascript - 基本的javascript;点击提醒

javascript - 从弹出窗口打开完整/常规浏览器窗口

iphone - 获取 iPhone 与 iPod Touch 时区的最佳实践

PHP,MySQL - 如何显示发布文章的正确时间取决于客户端时区

javascript - 如何使用 date-fns 猜测用户的时区?