Introduction
Some time in May I took a new job with Consolo Services, A web-based hospice management system, and things have been great. Also around this time, I started to play with Ruby 1.9 some, so our company decided to start developing with it, and deploy with REE still, until we know everything with 1.9 is kosher.
The Problem
One of the biggest problems we have had is this weird problem where string dates like “09/03/2009” would get saved in a date field as “03/09/2009”. What we didn’t know was that Ruby’s Date.parse() with Ruby 1.9 is now defaulting to the European date style where the format is “DD/MM/YYYY”, not “MM/DD/YYYY”. Bummer.
So we figured, hey no biggie, we’ll just override String’s to_date() method like so..
But that didn’t work for mass assignments, they were still swapping the days and months. So I put on my spelunking gear and started to look through ActiveRecord’s source code. I highly recommend doing this as there is some beautiful code (and not so beautiful) and since your using it, you should know it. I finally traced it back to activerecord-2.3.3/lib/active_record/connection_adapters/abstract/schema_definitions. This file holds the subclass ActiveRecord::ConnectionAdapters::Column. Go look at it, do it, now.
It all starts with the type_cast method, which tries to convert strings to the proper type like integer, float, boolean, date, etc. Then look at the string_to_date function. This function tries to call
def string_to_date(string)
return string unless string.is_a?(String)
return nil if string.empty?
fast_string_to_date(string) || fallback_string_to_date(string)
end
So the fast_string_to_date is for converting dates that are in the ISO format, like how they are stored in mysql. So that returns nil for us, and then goes to the fallback_string_to_date. This is where ActiveRecord calls Date.parse(), and since Date.parse is now using Euroean Dates, bam, you now have found the problem.
The Solution
So now all we have to do is override that method using our AmericanDateMonkeyPatch.
We save this file in the lib directory and require it in the environment.rb file, using config.after_initialization.
The Better Solution
I would to see some kind of way built into Rails or ActiveRecord that you could set an option to use American Date formats instead of European. Something that you could configure in Rails by saying ActiveRecord.use_american_dates to set that option. Nothing against the rest of the world, its just that we have a lot of users that are used to dates like this.
I hope this will save someone time and suffering, so please spread the word!

First of all, I think it's a bit weird that you're doing the String extension in a module (good) but instead of using a module for the ActiveRecord extension as well, you're just opening a class (bad). Put the stuff in a module and use extend - much nicer! Second, and way more important: For single locale applications, your approach is perfectly valid. Having a config option is not valid, at least not for internationalized apps - that would mean going back to pre-Rails 2.2 times where Rails didn't have internationalization support baked in and was stubborn and unruly when it came to everything but (American) English. The question you should ask yourself is not how you can make date parsing as simple as possible for you as a developer and your American users. Instead, the better option would be to come up with a solution that works transparently across different locales. I actually released a plugin for number and date parsing that tries to do exactly that - it's called delocalize and you can find it on http://github.com/clemens/delocalize. The advantage here is that it looks at the date formats you've defined in your locale files and parses the output based on these and the user's selected locale - so for American users, there just wouldn't be a DD/MM/YY format. Please do consider that there are other nations than the US and that they have widely different requirements in terms of formats (not only date formats).
Clemens, Thanks for you input and link to your plugin. I'll have to check it out, any possibly use it. That being said, yes we are definitely a single locale application and will only be a single locale application for the foreseeable future. And yes, I do appreciate the many different formats. But that wasn't the main reason for the post. The main reason was to give some people some heads up on why their dates are possibly switching the months and days when going to 1.9. This was not really apparent at first, and I couldn't find anything online about it.
Why not use the internationally unambiguous YYYY-MM-DD format for representing dates? This format leads you into the international standard time format, ISO 8601, which simply adds a T folowed by HH:MM:SS like so: YYYY-MM-DDTHH:MM:SS. It's so easy and intuitive. The units go from big to small as you read from left to right.
I personally would use that format, but to the thousands of users here, the MM/DD/YYYY style is how they prefer to input stuff, and how they have been doing for the last 3 years. It would cause havoc on our support email if we just up and changed it, not to mention the wraith from my bosses.
@clemens We had no intention of making a flexible date parsing utility. Ruby 1.9 has a vastly different parser to Ruby 1.8 and we would have liked to not make a patch at all. Once the decision was made to make the monkey patch, we had no obligations to any other locale, just don't load the patch and it would work as expected. We don't have to cater to any foreign locales since we have a medical application specific to the health care system in the States so multi-anything was the last thing on our list of concerns. Also, something strange we noticed was that ActiveRecord only converted to dates on access, so you could assign the string into a date column and until you used it, it would be fine. AR would access it and try and type cast it into database values and it would get the months and days all confused. That was actually round 2 of the plugin since we had no idea why we could convert a date using to_date on a string in the console and it would work and AR would do something else entirely. I tried to use a module to override the method with extend but i could never get the syntax just right to override the class method. Anyways, opening the class worked great. Sure, it's going to break with future releases, but we control those releases and hopefully we can throw the patch away. It would be fabulous. Actually making the date parser work like Ruby 1.8 would be the best. It had a heuristic where if you used dots (like Europeans seem inclined to do) it would parse it Euro-styled and if you used slashes (like Americans tend to do) it would parse it with the months and days reversed. Using the database format would be ideal since it is completely unambiguous but our user base is used to our legacy operation. Legacy sucks.
Is it a good idea to use the :default date format from environment.rb? We're using this at the moment: module ActiveRecord module ConnectionAdapters class Column class << self # patch date parsing so it uses the :default date format def fallback_string_to_date(string) fmt = ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS[:default] new_date(*::Date._strptime(string, fmt).values_at(:year, :mon, :mday)) end end end end