module ActionView::Helpers::DateHelper

def distance_of_time_in_words(from_time, to_time = 0, options = {})

distance_of_time_in_words(Time.now, Time.now) # => less than a minute
distance_of_time_in_words(to_time, from_time, include_seconds: true) # => about 6 years
distance_of_time_in_words(from_time, to_time, include_seconds: true) # => about 6 years
to_time = Time.now + 6.years + 19.days

distance_of_time_in_words(from_time, from_time + 4.years + 9.days + 30.minutes + 5.seconds) # => about 4 years
distance_of_time_in_words(from_time, from_time + 3.years + 6.months) # => over 3 years
distance_of_time_in_words(from_time, from_time + 1.year + 3.days) # => about 1 year
distance_of_time_in_words(from_time, 76.seconds.from_now) # => 1 minute
distance_of_time_in_words(from_time, from_time - 45.seconds, include_seconds: true) # => less than a minute
distance_of_time_in_words(from_time, from_time + 45.seconds, include_seconds: true) # => less than a minute
distance_of_time_in_words(from_time, from_time + 60.hours) # => 3 days
distance_of_time_in_words(from_time, 3.years.from_now) # => about 3 years
distance_of_time_in_words(from_time, from_time + 15.seconds, include_seconds: true) # => less than 20 seconds
distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute
distance_of_time_in_words(from_time, 50.minutes.from_now) # => about 1 hour
distance_of_time_in_words(from_time, from_time + 50.minutes) # => about 1 hour
from_time = Time.now

60-89 secs # => 1 minute
40-59 secs # => less than a minute
20-39 secs # => half a minute
10-19 secs # => less than 20 seconds
5-9 secs # => less than 10 seconds
0-4 secs # => less than 5 seconds
With include_seconds: true and the difference < 1 minute 29 seconds:

2 yrs <-> max time or date # => (same rules as 1 yr)
1 yr, 9 months <-> 2 yr minus 1 sec # => almost 2 years
1 yr, 3 months <-> 1 yr, 9 months # => over 1 year
1 yr <-> 1 yr, 3 months # => about 1 year
59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months
44 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 2 months
29 days, 23 hrs, 59 mins, 30 secs <-> 44 days, 23 hrs, 59 mins, 29 secs # => about 1 month
41 hrs, 59 mins, 30 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days
23 hrs, 59 mins, 30 secs <-> 41 hrs, 59 mins, 29 secs # => 1 day
89 mins, 30 secs <-> 23 hrs, 59 mins, 29 secs # => about [2..24] hours
44 mins, 30 secs <-> 89 mins, 29 secs # => about 1 hour
1 min, 30 secs <-> 44 mins, 29 secs # => [2..44] minutes
30 secs <-> 1 min, 29 secs # => 1 minute
0 <-> 29 secs # => less than a minute

Distances are reported based on the following table:
Pass include_seconds: true if you want more detailed approximations when distance < 1 min, 29 secs.
Reports the approximate distance in time between two Time, Date or DateTime objects or integers as seconds.
def distance_of_time_in_words(from_time, to_time = 0, options = {})
  options = {
    scope: :'datetime.distance_in_words'
  }.merge!(options)
  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)
  from_time, to_time = to_time, from_time if from_time > to_time
  distance_in_minutes = ((to_time - from_time)/60.0).round
  distance_in_seconds = (to_time - from_time).round
  I18n.with_options :locale => options[:locale], :scope => options[:scope] do |locale|
    case distance_in_minutes
      when 0..1
        return distance_in_minutes == 0 ?
               locale.t(:less_than_x_minutes, :count => 1) :
               locale.t(:x_minutes, :count => distance_in_minutes) unless options[:include_seconds]
        case distance_in_seconds
          when 0..4   then locale.t :less_than_x_seconds, :count => 5
          when 5..9   then locale.t :less_than_x_seconds, :count => 10
          when 10..19 then locale.t :less_than_x_seconds, :count => 20
          when 20..39 then locale.t :half_a_minute
          when 40..59 then locale.t :less_than_x_minutes, :count => 1
          else             locale.t :x_minutes,           :count => 1
        end
      when 2...45           then locale.t :x_minutes,      :count => distance_in_minutes
      when 45...90          then locale.t :about_x_hours,  :count => 1
      # 90 mins up to 24 hours
      when 90...1440        then locale.t :about_x_hours,  :count => (distance_in_minutes.to_f / 60.0).round
      # 24 hours up to 42 hours
      when 1440...2520      then locale.t :x_days,         :count => 1
      # 42 hours up to 30 days
      when 2520...43200     then locale.t :x_days,         :count => (distance_in_minutes.to_f / 1440.0).round
      # 30 days up to 60 days
      when 43200...86400    then locale.t :about_x_months, :count => (distance_in_minutes.to_f / 43200.0).round
      # 60 days up to 365 days
      when 86400...525600   then locale.t :x_months,       :count => (distance_in_minutes.to_f / 43200.0).round
      else
        if from_time.acts_like?(:time) && to_time.acts_like?(:time)
          fyear = from_time.year
          fyear += 1 if from_time.month >= 3
          tyear = to_time.year
          tyear -= 1 if to_time.month < 3
          leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count{|x| Date.leap?(x)}
          minute_offset_for_leap_year = leap_years * 1440
          # Discount the leap year days when calculating year distance.
          # e.g. if there are 20 leap year days between 2 dates having the same day
          # and month then the based on 365 days calculation
          # the distance in years will come out to over 80 years when in written
          # English it would read better as about 80 years.
          minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
        else
          minutes_with_offset = distance_in_minutes
        end
        remainder                   = (minutes_with_offset % MINUTES_IN_YEAR)
        distance_in_years           = (minutes_with_offset.div MINUTES_IN_YEAR)
        if remainder < MINUTES_IN_QUARTER_YEAR
          locale.t(:about_x_years,  :count => distance_in_years)
        elsif remainder < MINUTES_IN_THREE_QUARTERS_YEAR
          locale.t(:over_x_years,   :count => distance_in_years)
        else
          locale.t(:almost_x_years, :count => distance_in_years + 1)
        end
    end
  end
end