Fork me on GitHub

May 5, 2010

My Today went Yesterday

Post moved to http://log2.kares.org/post/59891237855/my-today-went-yesterday

It really did, making me unproductive around midnight as some of my unit test started failing. To be honest, I did fall asleep most of the times just by counting the failed assertions.

Now when a Rails test starts failing at a particular time during the day, there's probably some Time.zone misuse. But first let's do a recap here.
Testing time sensitive models or any time related behavior will sooner or later bend us to use Time.now. There's nothing wrong with that, as long as we keep in mind that when a model with a Time attribute value is saved and re-read there's a high chance it won't equal to the initial Time instance set. Most database vendor :datetime columns only use second precision and thus our time looses it's microsecond precision. Easy help, just use a custom time equality asserter:



However, this is not the only difference, after setting and reading the time attribute it holds a ActiveSupport::TimeWithZone instance. Rails performs this "conversion" to enable representing times in any time zone, as the standard Time is limited to UTC and the system zone. Well of course such times are equal no matter of the time zone. Issues might arise when times in different zones are converted to dates.
This starts to happen if You've configured ActiveRecord to store times in UTC (instead of the local time) which I do found very reasonable, as well as setting Time.zone to default to UTC (and adjusting it per request). For example, if You're GMT+0200 positive and write Time.now to an attribute, read it and convert to a Date object, it will start to return yesterday around midnight:


>> t1 = Time.parse "Tue May 04 00:00:00 +0200 2010"
=> Tue May 04 00:00:00 +0200 2010
>> t2 = t1.in_time_zone 'UTC'
=> Mon, 03 May 2010 22:00:00 UTC +00:00
>> t1.class
=> Time
>> t2.class
=> ActiveSupport::TimeWithZone
>> t1.to_date
=> Tue, 04 May 2010
>> t2.to_date
=> Mon, 03 May 2010

Here t2 is "simulating" the ActiveRecord conversion mechanism. Once we realize all that the test failures might be avoided by setting the Time.zone to your local time during tests:



And all the tests lived happily ever after ...

No comments:

Post a Comment