Distance_of_time_in_words fails in test

I have a DateTime object (from DateTime.now), and an
ActiveSupport::TimeWithZone object (comes from a date in the DB). I’m
passing these values to the helper method distance_of_time_in_words:

<%= distance_of_time_in_words(DateTime.now, @myinstance.mydate) %>

In the implementation of this helper is the following:

distance_in_minutes = (((to_time - from_time).abs)/60).round

In production, this works as expected. In testing, this results in:

ActionView::TemplateError: undefined method `abs’ for Sun Oct 26
19:49:44 UTC 1980:Time

Here’s where it gets strange. I opened this up in the debugger in
both environments. In test, a DateTime minus a TimeWithZone gives me
a Time. Time doesn’t have an abs method, so this fails with a
NoMethod exception. In production a DateTime minus a TimeWithZone
results in a Rational, which does have abs!

Why the different behavior in these two environments? I don’t see the
DateTime minus operator being redefined by rails anywhere, but maybe
I’m not looking in the right place. I’m using Rails version 2.2.2.

Actually, I was looking at the parameters in the wrong order. I need
the - operator from the to_date wich is the TimeWithZone. That’s
defined here:

def -(other)
  # If we're subtracting a Duration of variable length (i.e.,

years, months, days), move backwards from #time,
# otherwise move backwards #utc, for accuracy when moving across
DST boundaries
if other.acts_like?(:time)
utc - other
elsif duration_of_variable_length?(other)
method_missing(:-, other)
result = utc.acts_like?(:date) ? utc.ago(other) : utc - other
rescue utc.ago(other)

The rails console tells me I should hit the first condition, resulting
in a Time (which doesn’t support abs). I still haven’t found the
magic that makes this work in production.

Loading development environment (Rails 2.2.2)

a = DateTime.now
=> Sun, 05 Jul 2009 01:55:13 -0400

=> DateTime

b = Time.zone.now
=> Sun, 05 Jul 2009 05:55:31 UTC +00:00

=> ActiveSupport::TimeWithZone

=> Thu Jan 01 00:00:18 UTC 1970

=> Time

A little more information…

Not all ActiveSupport::TimeWithZone instances are alike. In the
definition of the minus operator (above) I consistantly see that
other.acts_like?(:time) so it always returns “utc-other”. The
difference is, the type of utc! When the TimeWithZone is created from
the DB, utc is a Date (and a Date - Date = rational). When the
TimeWithZone is created from a test fixture, utc is a Time (and a Time

  • Date = Time).

Now, at least, I understand how its possible that my subtraction is
returning a different type in each case. Unfortunately for me this
means the real answer is buried somewhere inside ActiceRecord code and
I’m still not smart enough to proceed. :slight_smile:

Two questions:

  1. Why isn’t anyone else hitting this? The combination of using test
    fixtures + calling distance_of_time_in_words can’t be THAT rare, can
  2. Any suggestions for a workaround?


Sometimes I’m too stubborn for my own good. Updating rails to 2.3.2
made this problem go away. The helper now works as I expect it to for
both DB dates and test fixture dates.