Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Glitch in DateHelper with timezones (#time_ago_in_words causing "undefined method 'abs'")

#3476

After I enabled Rails' new TimeZone features, I got this error in an obscure set of circumstances:

ActionView::TemplateError (undefined method `abs' for Thu Feb 19 13:59:51 -0500 1970:Time)

(The exception is is thrown by DateHelper#distance_of_time_in_words, called fromDateHelper#time_ago_in_words... it's not in the backtrace, but I confirmed it in a debugger.)

It appears that Time objects and ActiveSupport::TimeWithZone objects are getting mixed together, and when you try to take their difference, the resulting object doesn't always have an #abs method.

To fix it, I just patched #time_ago_in_words to use "Time.zone.now" instead of "Time.now":

module ActionView::Helpers::DateHelper
  def time_ago_in_words(from_time, include_seconds = false)
    distance_of_time_in_words(from_time, Time.zone.now, include_seconds)
  end
end

But this is a nasty hack. :)

Perhaps the default Time objects (DateTime, Time, etc.) should be patched to always return ActiveSupport::TimeWithZone objects when timezones are enabled?

(Rails version: 2.3.4)

Reported by epitron · November 10th, 2009 @ 09:51 AM

State: resolved
Milestone: none
Assigned to: Geoff Buesing Geoff Buesing
Importance: none

Activity

  1. Geoff Buesing
    Geoff Buesing
    • Assigned user set to Geoff Buesing

    I can't replicate this.

    With what arguments are you calling time_ago_in_words to get the error?

    November 10th, 2009 @ 02:36 PM

  2. epitron
    epitron

    The problem seems to stem from creating an ActiveSupport::TimeWithZone from a DateTime object:

    d = DateTime.parse("jan 7").in_time_zone
    

    If you go to the console, you'll notice that Time.now - d returns a Time object (no #abs), whereas Time.now - another_time_object gives you an integer.

    November 10th, 2009 @ 09:45 PM

  3. Geoff Buesing
    Geoff Buesing
    • State changed from new to open

    Aha, ok, I see what the issue is -- the instance of ActiveSupport::TimeWithZone you're creating is storing the time internally as a DateTime (because you started with DateTime.parse), and Time#- with a DateTime instance as an argument returns another instance of Time, instead of a Float.

    The fix should be easy enough -- we'll just need to add additional logic to Time#minus_with_coercion so that it returns a Float instead of a Time when a DateTime arg is supplied.

    The current Time#- behavior with a DateTime arg seems very broken, so I see no issues with fixing it -- see example below, I have no idea how anyone could be relying on this behavior:

    >> Time.local(2009,1,2) - DateTime.civil(2009,1,1)
    => Fri Jan 02 00:00:00 -0600 1970
    

    November 10th, 2009 @ 10:22 PM

  4. epitron
    epitron

    Ruby's standard library has a lot of potholes. :)

    November 10th, 2009 @ 11:19 PM

  5. Repository
    Repository

    (from [e98f9579c472e75f5a8c0678f2fc54b2d681e3ec]) Time#- with a DateTime argument behaves the same as with a Time argument, i.e. returns the difference between self and arg as a Float [#3476 status:resolved] http://github.com/rails/rails/commit/e98f9579c472e75f5a8c0678f2fc54...

    January 28th, 2010 @ 02:18 AM

  6. Repository
    Repository

    (from [3f7729a66eeb362d6d4f7b0add6ca40151794b74]) Time#- with a DateTime argument behaves the same as with a Time argument, i.e. returns the difference between self and arg as a Float [#3476 status:resolved] http://github.com/rails/rails/commit/3f7729a66eeb362d6d4f7b0add6ca4...

    January 28th, 2010 @ 02:25 AM

  7. Geoff Buesing
    Geoff Buesing

    Turns out the standard library isn't to blame -- ActiveSupport defines DateTime#to_f, so Time#- coerces the DateTime arg #to_f and assumes we're subtracting seconds, instead of finding the difference between two times.

    January 28th, 2010 @ 02:27 AM

  8. Geoff Buesing
    Geoff Buesing
    • State changed from open to resolved

    January 28th, 2010 @ 02:31 AM