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)
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.
Loading development environment (Rails 2.2.2)>> a = DateTime.now
=> Sun, 05 Jul 2009 01:55:13 -0400>> a.class
=> DateTime>> b = Time.zone.now
=> Sun, 05 Jul 2009 05:55:31 UTC +00:00>> b.class
=> ActiveSupport::TimeWithZone>> c=b-a
=> Thu Jan 01 00:00:18 UTC 1970>> c.class
=> Time>>
On Jul 5, 1:02 am, Brian
<butler.bria...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
wrote:> 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.
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. :) 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?
Resolved! 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. On Jul 5, 2:19 pm, Brian <butler.bria...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> 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. :) > > 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?