Date, Time and old days

Not so long ago a bug emerged on my current application, a vicious one.
Let’s say you have a user and store its bithday date in database (say MySQL) as a DateTime (yep I know, it’s a little to precise for this kind of data).
Rails conveniently retrieve this field as a Time, but as you probably do not be aware of is the range limitation of Time’s dates. In fact the Time class is often used because it’s faster than Date or DateTime, but the tradeoff is it handle date based on epoch time (01-01-1970), where Date/DateTime use Complex class and as such can handle a broader range of date.

Well, my user’s birthday date was somewhere in 60s and so can’t be handle by a the Time class. But it’s not as simple, Rails fallback to DateTime if parsing MySQL datetime field does not work with Time.parse. This results in an object perfectly valid when using it, the problem arise when you try to update the corresponding record in database.

Remember my initial datetime field was fetched as a DateTime ruby object and as Rails include all fields from the record on update it tries to translate the birthday to something MySQL recognize. ActiveSupport include some convenients methods to do that : Time#to_s and Date#to_s takes a parameter allowing us to do something like Time.today.to_s(:db) as well as some convenient Date to Time conversion. Unfortunately, no out of range detection is done in Date#to_time which leads me to the first headache. Then ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS hash does not contains a :db key so calling Date#to_s(:db) results in an erroneous string for the db. (this is corrected in rails edge but not in 1.2-stable branch).

All in all :

  1. be aware of Time class limitation
  2. ruby open classes are wonderful : just drop this code in your lib directory and that should make it until rails is patched.
module ActiveSupport
  module CoreExtensions
    module Date
      module Conversions
        # Add db and rfc822 format
        DATE_FORMATS.merge!({
          :db       => "%Y-%m-%d %H:%M:%S",
          :rfc822   => "%a, %d %b %Y %H:%M:%S %z"
        })
      end
    end
  end
end 

Thu, 23 Aug 2007 16:07 Posted in ,

Comment Date, Time and old days


RSS