【问题标题】:Correcting time for daylight savings in rails DateTime.parse在 Rails DateTime.parse 中更正夏令时的时间
【发布时间】:2012-08-16 21:09:14
【问题描述】:

只是增加了关于时区和 DST 问题的数百万个问题。

我有一个包含单独日期和时间字段的表单,我将它们组合起来创建一个 DateTime 像这样

start_time = DateTime.parse("#{parse_date(form_date)} #{form_start_time} #{Time.zone}")

如果我在 2012 年 8 月 21 日和 15:00 填写表单,那么这些就是我在重新加载表单时看到的值。如果我再查看模型中的 start_time 属性,它会正确设置为 Tue, 21 Aug 2012 15:00:00 EST +10:00

如果我在夏令时开始后使用今年晚些时候的日期(我在澳大利亚),则会出现问题。如果我使用 2012 年 12 月 21 日和 15:00,然后检查 start_time 我看到 Fri, 21 Dec 2012 16:00:00 EST +11:00

我对问题的解释是日期保存在我当前的时区 (+10:00) 中,因为这是我告诉 DateTime.parse 要做的事情。但是,当返回该值时,Rails 会查看日期并说“嘿,现在是 12 月的夏令时”并返回 +11:00 时区的时间。

如果 DST 生效,我想要做的是告诉 DateTime.parse 将时间保存在 +11:00 时区。显然将 Time.zone 传递到我的字符串中并不能实现这一点。有没有一种简单的方法可以做到这一点?我可以看到使用 Time#dst 的方法吗?但我怀疑这会创建一些非常难看的复杂代码。我认为可能有一种我缺少的内置方式。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 timezone


    【解决方案1】:

    (Rails 4.2.4 的答案,未检查旧版本或新版本)

    我建议使用in_time_zone String 方法,而不是使用固定班次 +01:00、+02:00 等,并将时区名称作为参数:

    夏令时:

    ruby :001 > "2016-07-02 00:00:00".in_time_zone('Paris')
     => Sat, 02 Jul 2016 00:00:00 CEST +02:00 
    

    冬令时:

    ruby :002 > "2016-11-02 00:00:00".in_time_zone('Paris')
     => Wed, 02 Nov 2016 00:00:00 CET +01:00 
    

    String#in_time_zone 相当于:

    ruby :003 > Time.find_zone!("Paris").parse("2016-07-02 00:00:00")
     => Sat, 02 Jul 2016 00:00:00 CEST +02:00 
    
    ruby :004 > Time.find_zone!("Paris").parse("2016-11-02 00:00:00")
     => Wed, 02 Nov 2016 00:00:00 CET +01:00 
    

    您可以通过以下方式获取时区名称:

    $ rake time:zones:all
    

    或者在 Rails 控制台中:

    ruby :001 > ActiveSupport::TimeZone.all.map(&:name)
    

    或者为选择标签构建集合:

    ActiveSupport::TimeZone.all.map do |timezone|
      formatted_offset = Time.now.in_time_zone(timezone.name).formatted_offset
      [ "(GMT#{formatted_offset}) #{timezone.name}", timezone.name ]
    end
    

    并存储时区名称而不是班次。

    注意:不要混淆String#in_time_zone 方法和Time#in_time_zone 方法。

    考虑我系统的时区是“巴黎”。

    ruby :001 > Time.parse("2016-07-02 00:00:00")
     => 2016-07-02 00:00:00 +0200 
    ruby :002 > Time.parse("2016-07-02 00:00:00").in_time_zone("Nuku'alofa")
     => Sat, 02 Jul 2016 11:00:00 TOT +13:00 
    

    【讨论】:

      【解决方案2】:

      到目前为止,这是我的解决方案。我希望有人有更好的。

      start_time = DateTime.parse "#{date} #{(form_start_time || start_time)} #{Time.zone}"
      start_time = start_time - 1.hour if start_time.dst? && !Time.now.dst?
      start_time = start_time + 1.hour if Time.now.dst? && start_time.dst?
      

      它似乎有效,但我没有严格测试它。我怀疑它可以被美化和缩短,但我认为这是可读和可以理解的。有什么改进吗?

      【讨论】:

      • 不应该是 Time.now.dst 吗? && !start_time.dst?
      • @brad,我知道这是一个很老的问题,但你有没有找到更好的方法来处理这个问题?如果没有,您是否发现这很好用?谢谢!
      【解决方案3】:

      我遇到了这个确切的问题。我的应用程序允许用户查看即将发生的事件。在美国,我们在 11 月 2 日是 DST,并且该日期及之后的所有事件都会提前一小时显示时间。

      我们需要有机会选择时区并将其存储到自己的字段中。在我使用以下内容存储我的日期时间之前:

      timezone_offset = Time.now.in_time_zone(params[:opportunity][:time_zone]).strftime("%z") #-0700
      DateTime.parse("#{params[:opportunity][:start_datetime]} #{timezone_offset}")
      

      要解决我已更改为的问题:

      start_datetime = Time.zone.parse(params[:opportunity][:start_datetime])
      

      显示我们使用的正确时间:

      @opportunity.start_datetime.in_time_zone(@opportunity.time_zone)
      

      【讨论】:

        【解决方案4】:

        我会尝试使用

        Australian Eastern Standard Time (AEST) (UTC +10).  
        Australian Central Standard Time (ACST) (UTC +9 ½).  
        Australian Western Standard Time (AWST) (UTC +8).  
        

        根据夏令时进行调整。

        【讨论】:

        • 我将如何以及在哪里设置这些。当我执行 rake time:zones:all 时,我没有看到列出的那些时区
        【解决方案5】:

        使用 Rails,我们可以为此使用 ActiveSupport::TimeZone:

        tz = ActiveSupport::TimeZone.new 'Pacific Time (US & Canada)'
        tz.parse(date_str_without_zone).to_datetime
        

        我使用TZip 从邮政编码中获取时区字符串(例如“太平洋时间(美国和加拿大)”)。

        【讨论】:

          【解决方案6】:

          如果您有自定义日期/时间格式,与 String#in_time_zone 支持的格式不同,您也可以使用(自 rails 5 起)strptime,例如:

          Time.find_zone!('Auckland').strptime('2021-02-02 08.00.00', '%Y-%m-%d %H.%M.%S')
          

          【讨论】:

            猜你喜欢
            • 2014-11-28
            • 1970-01-01
            • 1970-01-01
            • 2017-07-11
            • 2013-01-31
            • 2011-04-10
            • 1970-01-01
            • 2011-04-29
            • 2011-10-22
            相关资源
            最近更新 更多