And what factors would cause me to choose one or the other?
Time is a wrapper around POSIX-standard time_t, or seconds since January 1, 1970. This can be expressed as a positive or negative number, and is bounded:
Time.at(0x7FFFFFFF)
# => Mon Jan 18 22:14:07 -0500 2038
Time.at(-0x7FFFFFFF)
# => Fri Dec 13 15:45:53 -0500 1901
Values outside those bounds produce an error.
In contrast, DateTime is much more open-ended. The more robust version is a Ruby on Rails construct that serves as a wrapper around SQL-standard DATETIME fields. These contain arbitrary dates and can represent nearly any point in time as the range of expression is typically very large.
DateTime.new
# => Mon, 01 Jan -4712 00:00:00 +0000
So it's reassuring that DateTime can handle blog posts from Aristotle.
I think the answer to "what's the difference" is one of the unfortunate common answers to this question in the Ruby standard libraries: the two classes/libs were created differently by different people at different times. It's one of the unfortunate consequences of the community nature of Ruby's evolution compared to carefully planned development of something like Java. Developers want new functionality but don't want to step on existing APIs so they just create a new class - to the end user there's no obvious reason for the two to exist.
This is true for software libraries in general: often the reason some code or API is the way it is turns out to be historical rather than logical.
The temptation is to start with DateTime because it seems more generic. Date... and Time, right? Wrong. Time also does dates better, and in fact can parse timezones where DateTime can't. Also it performs better.
I've ended up using Time everywhere.
To be safe though, I tend to allow for DateTime arguments to be passed into my Timey APIs, and either convert. Also if I know that both have the method I'm interested in I accept either, like this method I wrote for converting times to XML (for XMLTV files)
# Will take a date time as a string or as a Time or DateTime object and
# format it appropriately for xmtlv.
# For example, the 22nd of August, 2006 at 20 past midnight in the British Summertime
# timezone (i.e. GMT plus one hour for DST) gives: "20060822002000 +0100"
def self.format_date_time(date_time)
if (date_time.respond_to?(:rfc822)) then
return format_time(date_time)
else
time = Time.parse(date_time.to_s)
return format_time(time)
end
end
# Note must use a Time, not a String, nor a DateTime, nor Date.
# see format_date_time for the more general version
def self.format_time(time)
# The timezone feature of DateTime doesn't work with parsed times for some reason
# and the timezone of Time is verbose like "GMT Daylight Saving Time", so the only
# way I've discovered of getting the timezone in the form "+0100" is to use
# Time.rfc822 and look at the last five chars
return "#{time.strftime( '%Y%m%d%H%M%S' )} #{time.rfc822[-5..-1]}"
end
The performance difference can't be emphasized enough... Time is C, and DateTime is Ruby:
>> Benchmark.bm do |bm|
?> bm.report('DateTime:') do
?> n1 = DateTime.now
>> n2 = DateTime.now
>> 1_000_000.times{ n1 < n2 }
>> end
>> bm.report('Time: ') do
?> n1 = Time.now
>> n2 = Time.now
>> 1_000_000.times{ n1 < n2 }
>> end
>> end
user system total real
DateTime: 4.980000 0.020000 5.000000 ( 5.063963)
Time: 0.330000 0.000000 0.330000 ( 0.335913)