【问题标题】:Ruby: combine Date and Time objects into a DateTimeRuby:将日期和时间对象组合成一个日期时间
【发布时间】:2012-08-29 15:30:12
【问题描述】:

简单的问题,但我找不到好的或明确的答案。将 Ruby 日期和时间对象(对象,而不是字符串)组合成单个 DateTime 对象的最佳和最有效的方法是什么?

【问题讨论】:

    标签: ruby


    【解决方案1】:

    使用seconds_since_midnight 时,夏令时的更改可能会导致意外结果。

    Time.zone = 'America/Chicago'
    t  = Time.zone.parse('07:00').seconds_since_midnight.seconds
    d1 = Time.zone.parse('2016-11-06').to_date # Fall back
    d2 = Time.zone.parse('2016-11-07').to_date # Normal day
    d3 = Time.zone.parse('2017-03-12').to_date # Spring forward
    
    d1 + t
    #=> Sun, 06 Nov 2016 06:00:00 CST -06:00
    d2 + t
    #=> Mon, 07 Nov 2016 07:00:00 CST -06:00
    d3 + t
    #=> Sun, 12 Mar 2017 08:00:00 CDT -05:00
    

    这是一个替代方案,类似于上面@selva-raj 的答案,使用字符串插值、strftimeparse%F 等于 %Y-%m-%d%T 等于 %H:%M:%S

    Time.zone = 'America/Chicago'
    t = Time.zone.parse('07:00')
    d1 = Time.zone.parse('2016-11-06').to_date # Fall back
    d2 = Time.zone.parse('2016-11-07').to_date # Normal day
    d3 = Time.zone.parse('2017-03-12').to_date # Spring forward
    
    Time.zone.parse("#{d1.strftime('%F')} #{t.strftime('%T')}")
    #=> Sun, 06 Nov 2016 07:00:00 CST -06:00
    Time.zone.parse("#{d2.strftime('%F')} #{t.strftime('%T')}")
    #=> Sun, 07 Nov 2016 07:00:00 CST -06:00
    Time.zone.parse("#{d3.strftime('%F')} #{t.strftime('%T')}")
    #=> Sun, 12 Mar 2017 07:00:00 CDT -05:00
    

    【讨论】:

    • 这是一个被低估的答案。如果您组合的日期是夏令时期间,而当前时间不是(反之亦然),除非您使用此答案中的一种方法,否则结果时间将相差一个小时。
    • 花了几个小时试图解决一个日期时间问题,因为我们刚刚更改了时间,所以事情发生了一个小时。阅读此答案后,我刚刚使用您的解决方案制作了一种方法,它完全解决了我一直在努力解决的问题。反响很好,2020年还是有用的!
    • 它适用于我Time.zone.parse("#{d1.strftime('%F')} #{t.strftime('%T')}")。谢谢!
    【解决方案2】:

    我找到了这个,但它没有你希望的那么优雅:

    d = Date.new(2012, 8, 29)
    t = Time.now
    dt = DateTime.new(d.year, d.month, d.day, t.hour, t.min, t.sec, t.zone)
    

    顺便说一句,ruby Time 对象还存储年、月和日,因此在创建 DateTime 时会丢弃它。

    【讨论】:

    • 这肯定不优雅,但是如何将它放入某种实用程序类并从那里使用它,例如:Utils.datetime_from_date_and_time(date, time) 或更短的东西。您的实用程序方法将包含一个不优雅的代码,但代码的用户将拥有一个方便且易读的工具。
    • 这个答案给我带来了很多夏令时的麻烦。生成的 DateTime 对象将位于当前时区,而不是基于日期的时区。如果您以 UTC 格式将其保存到数据库中(您应该这样做),那么当您尝试将其取回时,可能需要一个小时的时间。请参阅下面的@Alexander Clarke 的回答。
    • @JasonGluten - 只需使用 UTC 解析时间:Time.find_zone("UTC").parse(START_TIME)
    【解决方案3】:

    简单:

    Date.new(2015, 2, 10).to_datetime + Time.parse("16:30").seconds_since_midnight.seconds
    
    # => Object: Tue, 10 Feb 2015 16:30:00 +0000
    

    你一定会爱上 Ruby!

    【讨论】:

    • 如果你想保持时区,你可以这样做Date.new(2015, 2, 10).to_time + Time.parse("16:30").seconds_since_midnight.seconds
    • seconds_since_midnight 在使用时区和夏令时可能会导致意外结果。请参阅下面的答案。
    【解决方案4】:

    如果您使用的是 Ruby on Rails,则效果很好。

    我构建了一个方法来扩展 DateTime 类以组合日期和时间。 它从日期开始计算区域,这样它就不会在夏令时结束一个小时

    另外,为了方便起见,我也喜欢能够传入字符串。

    class DateTime
      def self.combine(d, t)
        # pass in a date and time or strings
        d = Date.parse(d) if d.is_a? String 
        t = Time.zone.parse(t) if t.is_a? String
        # + 12 hours to make sure we are in the right zone
        # (eg. PST and PDT switch at 2am)
        zone = (Time.zone.parse(d.strftime("%Y-%m-%d")) + 12.hours ).zone
        new(d.year, d.month, d.day, t.hour, t.min, t.sec, zone)
      end
    end
    

    所以你可以这样做:

    DateTime.combine(3.weeks.ago, "9am")
    

    DateTime.combine("2015-3-26", Time.current)
    

    等等……

    【讨论】:

      【解决方案5】:

      如果使用 Rails,请尝试以下任一方法:

      d = Date.new(2014, 3, 1) 
      t = Time.parse("16:30")
      
      dt = d + t.seconds_since_midnight.seconds   
      # => ActiveSupport::TimeWithZone
      
      dt = (d + t.seconds_since_midnight.seconds).to_datetime   
      # => DateTime
      
      dt = DateTime.new(d.year, d.month, d.day, t.hour, t.min, t.sec)   
      # => DateTime
      

      【讨论】:

      • dt = d + t.seconds_since_midnight.seconds 解决了我遇到的问题。
      【解决方案6】:

      我找到了另一种方法,我希望这是正确的。

       datetojoin=Time.parse(datetime).strftime("%Y-%m-%d")
             timetojoin=Time.parse(time).strftime("%T")          
             joined_datetime = Time.parse(datetojoin +" "+ timetojoin).strftime("%F %T")
      

      有什么想法吗?请分享。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-06
        相关资源
        最近更新 更多