Ryan Bigg
Ryan Bigg

Reputation: 107718

Calculating the distance between two times

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

Upvotes: 1

Views: 4214

Answers (2)

Daniel Vandersluis
Daniel Vandersluis

Reputation: 94113

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.

Upvotes: 2

paxdiablo
paxdiablo

Reputation: 881113

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).

Upvotes: 2

Related Questions