views:

371

answers:

2

I'm trying to make a "better" distance_of_time_in_words for rails and so far I have this: http://github.com/radar/dotiw.

However, at the moment it chokes on months + years, as shown by the specs. I'm at a complete loss! Help?

Code added by Pax so no-one else has to search through github:

module ActionView
  module Helpers
    module DateHelper
      def distance_of_time_in_words_hash(from_time, to_time)
        output = HashWithIndifferentAccess.new
        from_time = from_time.to_time if from_time.respond_to?(:to_time)
        to_time = to_time.to_time if to_time.respond_to?(:to_time)
        distance = from_time - to_time

        # Get a positive number.
        distance *= -1 if distance < 0

 

        while distance > 0
          if distance > 100000000000000
          elsif distance >= 31449600
            output[I18n.t(:years, :default => "years")], distance = 
              distance.divmod(31449600)
          elsif distance >= 2419200
            output[I18n.t(:months, :default => "months")], distance = 
              distance.divmod(2419200)
          elsif distance >= 604800
            output[I18n.t(:weeks, :default => "weeks")], distance = 
              distance.divmod(604800)
          elsif distance >= 86400
            output[I18n.t(:days, :default => "days")], distance =
              distance.divmod(86400)
          elsif distance >= 3600
            output[I18n.t(:hours, :default => "hours")], distance = 
              distance.divmod(3600)
          elsif distance >= 60
            output[I18n.t(:minutes, :default => "minutes")], distance = 
              distance.divmod(60)
          else
            output[I18n.t(:seconds, :default => "seconds")] = distance.to_i
            distance = 0
          end
        end
        output
      end

 

      def distance_of_time_in_words(from_time, to_time, include_seconds = false, 
          options = {}, output_options = {})

        hash = distance_of_time_in_words_hash(from_time, to_time)
        hash.delete(:seconds) if !include_seconds

        # Remove all the values that are nil.
        time_measurements = [
          I18n.t(:years, :default => "years"),
          I18n.t(:months, :default => "months"),
          I18n.t(:weeks, :default => "weeks"),
          I18n.t(:days, :default => "days"),
          I18n.t(:hours, :default => "hours"),
          I18n.t(:minutes, :default => "minutes"),
          I18n.t(:seconds, :default => "seconds")].delete_if do |key|
            hash[key].nil?
        end

        output = []
        time_measurements.each do |key|
          name = hash[key] > 1 ? key : key.singularize
          output += ["#{hash[key]} #{name}"]
        end

        output.to_sentence(output_options)
      end
    end
  end
end
+2  A: 

We too are at a complete loss. Perhaps you could make our lives easier by:

  • (1) posting the code (it's not that big) [forget this one, I've done it for you].
  • (2) tell us exactly what the correct behavior should be (desired output).
  • (3) tell us the behavior you're getting (sample actual output).

Then maybe we'll be able to do a better job.

One thing I've noticed straight up: there are not 2,419,200 seconds in any month other than February (and then only in non-leap years). Similarly, no year has 364 days.

I think you need to rethink how you're calculating the intervals.

Assuming that your "words" version of the duration can handle a little inaccuracy, at a bare minimum you should be using the averages for those figures (taking into account that a year is 365.2425 days which should be close enough for your purposes):

  • one year is 31,556,952 seconds.
  • one month is 2,629,746 seconds (simple divide by 12).
paxdiablo
The correct behaviour was described in the spec files. The errors can be gotten by running the spec files.
Ryan Bigg
I'm of the opinion that you should post all your stuff *here* on SO. What happens to the myriad of questions and answers that reference tinyurl or github sharing when those sites fold or decide to monetize their investment? To be honest, this is true even of Wikipedia, although less likely. Re your comment that I should just run your spec files, you'll find you get more help the more *you* put into it. It would have been so much easier had you posted everything here and actually described what the problem was rather than just saying "run the spec file".
paxdiablo
+1  A: 

It looks like you're trying to get the time difference in terms of all applicable units (ie. "2 years, 4 months, 7 days" instead of "2 years" which Rails' distance_of_time_in_words gives)?

If so, check out In Rails, display time between two dates in English, another SO question about displaying time differences. My answer there should give you a good starting point for what you seem to be trying to do, and it wouldn't be hard to extend the method to include hours, minutes and seconds.

Daniel Vandersluis
Very similar to what I already had still does not produce correct results, but I do prefer your method of using the numeric helpers vs "magic numbers"
Ryan Bigg