I will construct a method relative_time that has two arguments:
- date_timean instance of DateTime that specifies a time in the past; and
- time_unit, one of- :SECONDS,- :MINUTES,- :HOURS,- :DAYS,- :WEEKS,- :MONTHSor- :YEARS, specifying the unit of time for which the difference in time between the current time and- date_timeis to be expressed.
Code
require 'date'
TIME_UNIT_TO_SECS = { SECONDS:1, MINUTES:60, HOURS:3600, DAYS:24*3600,
                      WEEKS: 7*24*3600 }
TIME_UNIT_LBLS    = { SECONDS:"seconds", MINUTES:"minutes", HOURS:"hours",
                      DAYS:"days", WEEKS: "weeks", MONTHS:"months",
                      YEARS: "years" }
def relative_time(date_time, time_unit)
  now = DateTime.now
    raise ArgumentError, "'date_time' cannot be in the future" if
      date_time > now
  v = case time_unit
      when :SECONDS, :MINUTES, :HOURS, :DAYS, :WEEKS
        (now.to_time.to_i-date_time.to_time.to_i)/
          TIME_UNIT_TO_SECS[time_unit]
      when :MONTHS
        0.step.find { |n| (date_time >> n) > now } -1
      when :YEARS
        0.step.find { |n| (date_time >> 12*n) > now } -1
      else
        raise ArgumentError, "Invalid value for 'time_unit'"
      end
  puts "#{v} #{TIME_UNIT_LBLS[time_unit]} ago"
end
Examples
date_time = DateTime.parse("2020-5-20")
relative_time(date_time, :SECONDS)
5870901 seconds ago
relative_time(date_time, :MINUTES)
97848 minutes ago
relative_time(date_time, :HOURS)
1630 hours ago
relative_time(date_time, :DAYS)
67 days ago
relative_time(date_time, :WEEKS)
9 weeks ago
relative_time(date_time, :MONTHS)
2 months ago
relative_time(date_time, :YEARS)
0 years ago
Explanation
If time_unit equals :SECONDS, :MINUTES, :HOURS, :DAYS or :WEEKS I simply compute the number of seconds elapsed between date_time and the current time, and divide that by the number of seconds per the given unit of time. For example, if time_unit equals :DAYS the elapsed time in seconds is divided by 24*3600, as there are that many seconds per day.
If time_unit equals :MONTHS, I use the method Date#>> (which is inherited by DateTime) to determine the number of months that elapse from date_time until a time is reached that is after the current time, then subtract 1.
The calculation is similar if time_unit equals :YEARS: determine the number of years that elapse from date_time until a time is reached that is after the current time, then subtract 1.
One could require the user to enter a Time instance (rather than a DateTime instance) as the first argument. That would not simplify the method, however, as the Time instance would have to be converted to a DateTime instance when time_unit equals :MONTH or :YEAR, to use the method Date#>>.