【问题标题】:Can't set timezone using abbreviation无法使用缩写设置时区
【发布时间】:2015-08-25 17:01:13
【问题描述】:

我无法在 Rails 上使用其缩写设置时区,例如:

>> Time.zone = 'BRT'
ArgumentError: Invalid Timezone: BRT
        from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-3.2.21/lib/active_support/core_ext/time/zones.rb:61:in `rescue in find_zone!'
        from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-3.2.21/lib/active_support/core_ext/time/zones.rb:53:in `find_zone!'
        from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-3.2.21/lib/active_support/core_ext/time/zones.rb:37:in `zone='
        from (irb):14
        from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-3.2.21/lib/rails/commands/console.rb:47:in `start'
        from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-3.2.21/lib/rails/commands/console.rb:8:in `start'
        from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-3.2.21/lib/rails/commands.rb:41:in `<top (required)>'
        from script/rails:6:in `require'
        from script/rails:6:in `<main>'

这是必要的,因为某些系统(android 和某些浏览器)使用缩写报告时区。 缩写列表可以在http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations找到。

【问题讨论】:

  • 您希望对不明确的缩写产生什么影响?基本上,您应该避免使用缩写作为指定时区的一种方式。有多种方法可以在 JavaScript 中检测时区,如果这对您有帮助...
  • 嘿乔恩,是的,jstz 正在使用缩写报告时区,请参阅bitbucket.org/pellepim/jstimezonedetect/issue/116/…。你推荐其他图书馆吗?
  • 我建议你找一个不同的,是的。我没有任何具体的建议,但我知道有很多可用的。

标签: ruby-on-rails timezone activesupport


【解决方案1】:

jstimezone 使用缩写报告时区。它也很容易出错且无人维护 (https://bitbucket.org/pellepim/jstimezonedetect/issues?status=new&status=open)。只使用标准 javascript 更简单:

var offset = - new Date().getTimezoneOffset()/60

然后调用准备好的文档:

$.cookie("browser.tzoffset", offset, { expires: 30, path: '/' })

然后在 Rails 中使用 around_filter in ApplicationController:

  def set_time_zone
    return yield unless (utc_offset = cookies['browser.tzoffset']).present?
    utc_offset = utc_offset.to_i
    gmt_offset = if utc_offset == 0 then nil elsif utc_offset > 0 then -utc_offset else "+#{-utc_offset}" end
    Time.use_zone("Etc/GMT#{gmt_offset}"){ yield }
  rescue ArgumentError
    yield
  end

这将为用户本地化所有日期,独立于他/她所在的位置。例如,在巴西,我们有多个时区。

PS:ActiveSupport::TimeZone[utc_offset.to_i] 无法使用,因为它使用 DST,请参阅https://github.com/rails/rails/issues/20504

PS:你也可以使用moment:moment.parseZone(Date.now()).utcOffset()/60moment().format('zz')

【讨论】:

  • Uhhh... jsTimeZoneDetect 不返回缩写。它返回时区,例如America/New_York。如果它返回一个缩写,你应该把它作为一个错误提出。
  • 另外,使用getTimeZoneOffset 不适用于时区检测,因为它只返回调用它的Date 对象的偏移量。由于您在 new Date() 上调用它,因此它返回代码运行所在时区的 current 偏移量。您不能只获取偏移量并将其映射回时区,因为许多时区共享相同的偏移量,并在一年中的不同时间使用它们。请参阅the timezone tag wiki 中的“时区!= 偏移量”。
  • matt,这个答案的重点是将日期从数据库本地化到向特定用户展示。所以用户的时区并不重要。
  • 也许你可以使用Intl.DateTimeFormat().resolved.timeZone
  • @Andy Intl.DateTimeFormat().resolved.timeZone 正在使用 Chrome 的某些 Android 设备上返回时区缩写。
【解决方案2】:

您不必使用 around_filter。 把这个放在before_action

Time.zone = "Etc/GMT#{gmt_offset}"

(Time.zone 是线程本地的。更改是安全的。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-16
    • 2023-04-04
    • 1970-01-01
    • 2012-03-26
    • 2020-09-13
    • 2010-12-29
    • 1970-01-01
    相关资源
    最近更新 更多