Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
392 views
in Technique[技术] by (71.8m points)

ruby - Are the Date, Time, and DateTime classes necessary?

What is the purpose of having Date and Time classes when there is a DateTime class that can handle both?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

To summarize what the common ruby time classes are:

Time

This is the basic workhorse core ruby time class.

  • Has date and time attributes (year, month, day, hour, min, sec, subsec)
  • Based on floating-point second intervals from unix epoch (1970-01-01)
  • Can handle negative times before unix epoch
  • Can handle time arithmetic in units of seconds
  • Natively works in either UTC or "local" (system time zone)

There are really 3 kinds of Time object when it comes to dealing with time zones, let's look at a summer time to show DST:

utc = Time.utc(2012,6,1) # => 2012-12-21 00:00:00 UTC
utc.zone       # => "UTC"
utc.dst?       # => false
utc.utc?       # => true
utc.utc_offset # => 0

local = Time.local(2012,6,1) # => 2012-06-01 00:00:00 -0700
local.zone       # => "PDT"
local.dst?       # => true
local.utc?       # => false
local.utc_offset # => -25200

nonlocal = Time.new(2012,6,1,0,0,0, "-07:00") # => 2012-06-01 00:00:00 -0700
nonlocal.zone       # => nil
nonlocal.dst?       # => false
nonlocal.utc?       # => false
nonlocal.utc_offset # => -25200

The last 2 look similar, but beware: you should not do arithmetic with a non-local Time. This is simply a time with a UTC offset and no zone, so it doesn't know the rules of DST. Adding time over the DST boundary will not change the offset and the resulting time-of-day will be wrong.

ActiveSupport::TimeWithZone

This one is worth mentioning here since it's what you use in Rails. Same as Time, plus:

  • Can handle any time zone
  • Respects DST
  • Can convert times between zones

I generally always reach for this when ActiveSupport is available as it takes care of all the time zone pitfalls.

Date

  • Has date attributes only (year, month, day)
  • Based on integer whole-day intervals from an arbitrary "day zero" (-4712-01-01)
  • Can handle date arithmetic in units of whole days
  • Can convert between dates in the ancient Julian calendar to modern Gregorian

Date is more useful than Time whenever you deal in whole days: no time zones to worry about! (I'm surprised this doesn't deal with the modern Persian calendar since it knows about the obsolete Julian calendar from centuries ago.)

DateTime

  • Has date and time attributes (year, month, day, hour, min, sec)
  • Based on fractions of whole-day intervals from an arbitrary "day zero" (-4712-01-01)
  • Can handle date arithmetic in units of whole days or fractions

Personally, I never have reason to use this: it's slow, it handles time without considering time zones, and it has an inconsistent interface. I find it leads to confusion whenever you assume you have a Time-like object, but it actually behaves like a Date instead:

Time.new(2012, 12, 31, 0, 0, 0) + 1 == Time.new(2012, 12, 31, 0, 0, 1)
DateTime.new(2012, 12, 31, 0, 0, 0) + 1 == DateTime.new(2013, 1, 1, 0, 0, 0)

Further, it has a meaningless "zone" attribute (note how non-local Time objects warn you that zone == nil), and you can't know anything else about it before turning it into a Time first:

dt = DateTime.new(2012,12,6, 1, 0, 0, "-07:00")
dt.zone # => "-07:00"
dt.utc? # => NoMethodError: undefined method `utc?'
dt.dst? # => NoMethodError: undefined method `dst?'
dt.utc_offset # => NoMethodError: undefined method `utc_offset'

Dealing with microseconds to check for rounding is also a little strange. You would think that because it doesn't have a usec attribute that it only deals in whole numbers, but you'd be wrong:

DateTime.now.usec # => NoMethodError: undefined method `usec'
DateTime.now.to_time.usec => 629399

In short, unless you're dealing with astronomical events in the ancient past and need to convert the Julian date (with time of day) to a modern calendar, please don't use DateTime. If anyone has an actual use case for this class, I'd love to read your comments.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...