This page contains automated test results for code from O'Reilly's Ruby Cookbook. If this code looks interesting or useful, you might want to buy the whole book.

Converting Between Time and DateTime Objects
CodeExpectedActual
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
time = Time.gm(2000, 6, 4, 10, 30, 22, 4010)    
Sun Jun 04 10:30:22 UTC 2000 Sun Jun 04 10:30:22 UTC 2000
time.to_datetime.to_s
"2000-06-04T10:30:22Z" "2000-06-04T10:30:22Z"
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
(datetime = DateTime.new(1990, 10, 1, 22, 16, Rational(41,2))).to_s
"1990-10-01T22:16:20Z" "1990-10-01T22:16:20Z"
datetime.to_gm_time
Mon Oct 01 22:16:20 UTC 1990 Mon Oct 01 22:16:20 UTC 1990
datetime.to_local_time
Mon Oct 01 17:16:20 EDT 1990 Mon Oct 01 17:16:20 EDT 1990
time < datetime
ArgumentError: comparison of Time with DateTime failed
...
ArgumentError: comparison of Time with DateTime failed
	from (irb):32:in `<'
	from (irb):32
time.to_datetime < datetime
false false
time < datetime.to_gm_time
false false
time - datetime
TypeError: can't convert DateTime into Float
...
TypeError: can't convert DateTime into Float
	from (irb):35:in `-'
	from (irb):35
(time.to_datetime - datetime).to_f
3533.50973962975 3533.50973962975
time - datetime.to_gm_time
305295241.50401 305295241.50401
time
Sun Jun 04 10:30:22 UTC 2000 Sun Jun 04 10:30:22 UTC 2000
time.usec
4010 4010
time.to_datetime.to_gm_time
Sun Jun 04 10:30:22 UTC 2000 Sun Jun 04 10:30:22 UTC 2000
time.to_datetime.to_gm_time.usec
4010 4010
datetime.to_s
"1990-10-01T22:16:20Z" "1990-10-01T22:16:20Z"
datetime.to_gm_time.to_datetime.to_s
"1990-10-01T22:16:20Z" "1990-10-01T22:16:20Z"
def normalize_time_types(array)
  # Don't do anything if all the objects are already of the same type.
  first_class = array[0].class
  first_class = first_class.super if first_class == DateTime
  return unless array.detect { |x| !x.is_a?(first_class) }
  normalized = array.collect do |t| 
    if t.is_a?(Date)
      begin 
        t.to_local_time
      rescue ArgumentError # Time out of range; convert to DateTimes instead.
        convert_to = DateTime
        break
      end
    else
      t
    end
  end
  unless normalized
    normalized = array.collect { |t| t.is_a?(Time) ? t.to_datetime : t }
  end
  return normalized
end
mixed_array = [Time.now, DateTime.now]
[Sat Mar 18 22:17:10 EST 2006, [Mon Mar 27 16:43:32 EST 2006, #<DateTime: 3312660247072381/1350000000,-5/24,2299161>]
normalize_time_types(mixed_array)
[Sat Mar 18 22:17:10 EST 2006, Sun Mar 19 03:17:10 EST 2006] [Mon Mar 27 16:43:32 EST 2006, Mon Mar 27 21:43:32 EST 2006]
mixed_array << DateTime.civil(1776, 7, 4)
normalize_time_types(mixed_array).collect { |x| x.to_s }
["2006-03-18T22:17:10-0500", "2006-03-18T22:17:10-0500", ["2006-03-27T16:43:32-0500", "2006-03-27T16:43:32-0500", "1776-07-04T00:00:00Z"]