Convert to/from DateTime and Time in Ruby

后端 未结 6 1382
挽巷
挽巷 2020-11-29 16:44

How do you convert between a DateTime and a Time object in Ruby?

相关标签:
6条回答
  • 2020-11-29 16:58

    While making such conversions one should take into consideration the behavior of timezones while converting from one object to the other. I found some good notes and examples in this stackoverflow post.

    0 讨论(0)
  • 2020-11-29 17:03

    As an update to the state of the Ruby ecosystem, Date, DateTime and Time now have methods to convert between the various classes. Using 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
    
    0 讨论(0)
  • 2020-11-29 17:05
    require 'time'
    require 'date'
    
    t = Time.now
    d = DateTime.now
    
    dd = DateTime.parse(t.to_s)
    tt = Time.parse(d.to_s)
    
    0 讨论(0)
  • 2020-11-29 17:08

    You'll need two slightly different conversions.

    To convert from Time to DateTime you can amend the Time class as follows:

    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
    

    Similar adjustments to Date will let you convert DateTime to 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
    

    Note that you have to choose between local time and GM/UTC time.

    Both the above code snippets are taken from O'Reilly's Ruby Cookbook. Their code reuse policy permits this.

    0 讨论(0)
  • 2020-11-29 17:12

    Improving on Gordon Wilson solution, here is my try:

    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
    

    You'll get the same time in UTC, loosing the timezone (unfortunately)

    Also, if you have ruby 1.9, just try the to_time method

    0 讨论(0)
  • 2020-11-29 17:21

    Unfortunately, the DateTime.to_time, Time.to_datetime and Time.parse functions don't retain the timezone info. Everything is converted to local timezone during conversion. Date arithmetics still work but you won't be able to display the dates with their original timezones. That context information is often important. For example, if I want to see transactions performed during business hours in New York I probably prefer to see them displayed in their original timezones, not my local timezone in Australia (which 12 hrs ahead of New York).

    The conversion methods below do keep that tz info.

    For Ruby 1.8, look at Gordon Wilson's answer. It's from the good old reliable Ruby Cookbook.

    For Ruby 1.9, it's slightly easier.

    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
    

    This prints the following

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

    The full original DateTime info including timezone is kept.

    0 讨论(0)
提交回复
热议问题