Liquid Media's Apps

Guessing Centuries

ActiveRecord is really clever. If you declare a database column foo as type integer, whenever you declare:

foo = "5"

ActiveRecord converts the string "5" into the integer 5. Similarly, if column bar is type date, then:

bar = 'December 20, 2007'

is converted* to a Date object, using the ParseDate.parsedate method**.

However, while Rails is clever, it doesn't want to be too clever. If you say bar = '20.12.07', it thinks you're referring to 20 December, 0007 — like when Jesus was about 13 years old. For a project that I'm working on, where dates would often be copy-and-pasted from other web sites, this default was not acceptable.

To "correct" this behaviour, I added a file lib/overrides.rb whose contents are:

module ActiveRecord
  module ConnectionAdapters #:nodoc:
    class Column
      class << self
        def fallback_string_to_date(string)
          new_date *ParseDate.parsedate(string, true)[0..2]

The part that changed from the original method, the ", true" is shown in bold above. Now the software chooses more sensible (for our context) default centuries by using the comp feature of parsedate (see the RDoc).

*It's not quite as simple as I'm describing it above. The value is stored as you entered it in the @attributes hash and when you get the attribute (using Object#attribute_name) you're actually calling the read_attribute method which does an implicit type cast for you. You have at your disposal a Object#attribute_name_before_type_cast method that returns the content as you entered it.

**Aside: ParseDate.parsedate seems pretty arbitrary about whether it uses a month-then-day (U.S.) or day-then-month (Europe and most of the rest of the world). 10-12-2007 is dd-mm-yyyy but 10.12.2007 is mm.dd.yyyy, which is strange because Europe (well, Germany at least) tends to use periods in dates, but ParseDate treats that as an American format.

Tagged activerecord, date parsing, monkey patching, parsedate, and rails.
blog comments powered by Disqus