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:
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)
else
result = utc.acts_like?(:date) ? utc.ago(other) : utc - other
rescue utc.ago(other)
result.in_time_zone(time_zone)
end
end
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.
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.
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
it?
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.