views:

330

answers:

3

If I have a time variable in Ruby, how could I say that it refers to an event that happened one of the following:

"x minutes ago" or "x hours ago" or "x days ago"

Obviously if something happened 2 days ago, I would not want to say it happened such-and-such minutes ago.

A: 

You need to do something like this:

tnow = Time.now
elapsed = tnow - tevent # elapsed time in seconds

if (elapsed < 60)
  puts "#{elapsed} seconds ago"
elsif (elapsed < 60*60)
  puts "#{elapsed/60} minutes ago"
end
kgiannakakis
Wow, I didn't realize that Ruby was so clever it could tell that *elapsed* and *epapsed* referred to the same variable :-)
paxdiablo
@Pax: why not just edit the (two) obvious typos?
Telemachus
I rarely edit other people's posts when they're new, I guess I expect them to keep an eye on them and fix them. If it's stayed like that for a few days, I might do it. Case in point was a recent answer that used the phrase "gank it off the website" - I thought it was meant to be "yank" but no, apparently that's a word (albeit possibly slang). OP would probably been pissed off if I'd changed it.
paxdiablo
@Pax: fair enough for 'gank', but in a case like this, both `(` and `epapsed` were clearly typos.
Telemachus
+6  A: 

If you are on rails:

time_ago_in_words
Juri Glass
API Reference: http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#M001696
jleedev
And the source code for the method in question, in case you don't happen to be on Rails: http://dev.rubyonrails.org/browser/trunk/actionpack/lib/action_view/helpers/date_helper.rb?rev=4674#L24
jleedev
+5  A: 

Here's the language agnostic version which you should be able to convert into any language:

ONE_MINUTE = 60
ONE_HOUR = 60 * ONE_MINUTE
ONE_DAY = 24 * ONE_HOUR
ONE_WEEK = 7 * ONE_DAY
ONE_MONTH = ONE_DAY * 3652425 / 120000
ONE_YEAR = ONE_DAY * 3652425 / 10000

def when(then):
    seconds_ago = now() - then

    if seconds_ago < 0:
        return "at some point in the future (???)"
    if seconds_ago == 0:
        return "now"

    if seconds_ago == 1:
        return "1 second ago"
    if seconds_ago < ONE_MINUTE:
        return str(seconds_ago) + "seconds ago"

    if seconds_ago < 2 * ONE_MINUTE:
        return "1 minute ago"
    if seconds_ago < ONE_HOUR:
        return str(seconds_ago/ONE_MINUTE) + "minutes ago"

    if seconds_ago < 2 * ONE_HOUR:
        return "1 hour ago"
    if seconds_ago < ONE_DAY:
        return str(seconds_ago/ONE_HOUR) + "hours ago"

    if seconds_ago < 2 * ONE_DAY:
        return "1 day ago"
    if seconds_ago < ONE_WEEK:
        return str(seconds_ago/ONE_DAY) + "days ago"

    if seconds_ago < 2 * ONE_WEEK:
        return "1 week ago"
    if seconds_ago < ONE_MONTH:
        return str(seconds_ago/ONE_WEEK) + "weeks ago"

    if seconds_ago < 2 * ONE_MONTH:
        return "1 month ago"
    if seconds_ago < ONE_YEAR:
        return str(seconds_ago/ONE_MONTH) + "months ago"

    if seconds_ago < 2 * ONE_YEAR:
        return "1 year ago"
    return str(seconds_ago/ONE_YEAR) + "years ago"

Note that the year/month figures are approximate (based on averages) but that shouldn't really matter since the relative error will still be very low.

paxdiablo