首页 文章

在Ruby中转换为DateTime和Time

提问于
浏览
126

如何在Ruby中的DateTime和Time对象之间进行转换?

5 回答

  • 9

    您需要两次稍有不同的转换 .

    要将 Time 转换为 DateTime ,您可以按如下方式修改Time类:

    require 'date'
    class Time
      def to_datetime
        # Convert seconds + microseconds into a fractional number of seconds
        seconds = sec + Rational(usec, 10**6)
    
        # Convert a UTC offset measured in minutes to one measured in a
        # fraction of a day.
        offset = Rational(utc_offset, 60 * 60 * 24)
        DateTime.new(year, month, day, hour, min, seconds, offset)
      end
    end
    

    对Date的类似调整将允许您将 DateTime 转换为 Time .

    class Date
      def to_gm_time
        to_time(new_offset, :gm)
      end
    
      def to_local_time
        to_time(new_offset(DateTime.now.offset-offset), :local)
      end
    
      private
      def to_time(dest, method)
        #Convert a fraction of a day to a number of microseconds
        usec = (dest.sec_fraction * 60 * 60 * 24 * (10**6)).to_i
        Time.send(method, dest.year, dest.month, dest.day, dest.hour, dest.min,
                  dest.sec, usec)
      end
    end
    

    请注意,您必须在本地时间和GM / UTC时间之间进行选择 .

    以上代码片段均取自O 'Reilly' s Ruby Cookbook . 他们的代码重用policy允许这样做 .

  • 59
    require 'time'
    require 'date'
    
    t = Time.now
    d = DateTime.now
    
    dd = DateTime.parse(t.to_s)
    tt = Time.parse(d.to_s)
    
  • 1

    作为Ruby生态系统状态的更新, DateDateTimeTime 现在具有在各种类之间进行转换的方法 . 使用Ruby 1.9.2:

    pry
    [1] pry(main)> ts = 'Jan 1, 2000 12:01:01'
    => "Jan 1, 2000 12:01:01"
    [2] pry(main)> require 'time'
    => true
    [3] pry(main)> require 'date'
    => true
    [4] pry(main)> ds = Date.parse(ts)
    => #<Date: 2000-01-01 (4903089/2,0,2299161)>
    [5] pry(main)> ds.to_date
    => #<Date: 2000-01-01 (4903089/2,0,2299161)>
    [6] pry(main)> ds.to_datetime
    => #<DateTime: 2000-01-01T00:00:00+00:00 (4903089/2,0,2299161)>
    [7] pry(main)> ds.to_time
    => 2000-01-01 00:00:00 -0700
    [8] pry(main)> ds.to_time.class
    => Time
    [9] pry(main)> ds.to_datetime.class
    => DateTime
    [10] pry(main)> ts = Time.parse(ts)
    => 2000-01-01 12:01:01 -0700
    [11] pry(main)> ts.class
    => Time
    [12] pry(main)> ts.to_date
    => #<Date: 2000-01-01 (4903089/2,0,2299161)>
    [13] pry(main)> ts.to_date.class
    => Date
    [14] pry(main)> ts.to_datetime
    => #<DateTime: 2000-01-01T12:01:01-07:00 (211813513261/86400,-7/24,2299161)>
    [15] pry(main)> ts.to_datetime.class
    => DateTime
    
  • 177

    遗憾的是, DateTime.to_time, Time.to_datetimeTime.parse 函数无法显示具有原始时区的日期 . 上下文信息通常很重要 . 例如,如果我想看到在纽约工作时间执行的交易,我可能更愿意看到它们显示在原始时区,而不是我在澳大利亚的当地时区(比纽约提前12小时) .

    下面的转换方法确实保留了tz信息 .

    对于Ruby 1.8,请查看Gordon Wilson's answer . 这是来自古老可靠的Ruby Cookbook .

    对于Ruby 1.9,它稍微容易一些 .

    require 'date'
    
    # Create a date in some foreign time zone (middle of the Atlantic)
    d = DateTime.new(2010,01,01, 10,00,00, Rational(-2, 24))
    puts d
    
    # Convert DateTime to Time, keeping the original timezone
    t = Time.new(d.year, d.month, d.day, d.hour, d.min, d.sec, d.zone)
    puts t
    
    # Convert Time to DateTime, keeping the original timezone
    d = DateTime.new(t.year, t.month, t.day, t.hour, t.min, t.sec, Rational(t.gmt_offset / 3600, 24))
    puts d
    

    这将打印以下内容

    2010-01-01T10:00:00-02:00
    2010-01-01 10:00:00 -0200
    2010-01-01T10:00:00-02:00
    

    保留包含时区的完整原始日期时间信息 .

  • 47

    改进Gordon Wilson解决方案,这是我的尝试:

    def to_time
      #Convert a fraction of a day to a number of microseconds
      usec = (sec_fraction * 60 * 60 * 24 * (10**6)).to_i
      t = Time.gm(year, month, day, hour, min, sec, usec)
      t - offset.abs.div(SECONDS_IN_DAY)
    end
    

    您将在UTC中获得相同的时间,丢失时区(不幸的是)

    此外,如果你有ruby 1.9,只需尝试 to_time 方法

相关问题