What you need to do to win this challenge is to write the shortest "timeago" script that outputs the number of decades, years, weeks, days, hours, minutes, and seconds between a given Unix timestamp and the time the script is run.

You must give the time difference in "lowest terms", e.g. 1 week not 7 days, 9 years not 0 decades 9 years. You also must use plural forms correctly, e.g. 1 day not 1 days.

Your script must be accurate to within plus or minus 1 second (so the exact second rounding method is unimportant).

Time Equivalency Table
1 decade = 10 years
1 year = 31536000 seconds (not technically correct but close enough)
1 week = 7 days
1 day = 24 hours
1 hour = 60 minutes
1 minute = 60 seconds

The output should be of the form

A decade(s) B year(s) C week(s) D day(s) E hour(s) F minute(s) G second(s)

where A...G are all non-negative integers and the s is only there for plurals.


  • The timestamp will always be a time from the past. It may be negative.
  • Input and output may be anything reasonable: stdin/stdout, function input and return value, etc.
  • You may not use any tools that already do this. i.e. if your language has a timesince(timestamp) function built in you may not use that function.

I have vastly edited this to make it clearer in hopes to assuage the somewhat silly battle between new users with unclear questions and old users who require perfection. It was not a terrible question (though now it may be too similar to this).

Given that enough time is passed since the last answer, I declare Three If By Whiskey with its 177 bytes Ruby implementation the winner of this context!

  • 2
    \$\begingroup\$ "In the case of Javascript JQuery is forbidden :P Everything else is ok." -- is Zepto allowed, then? \$\endgroup\$ Aug 23, 2014 at 17:40
  • 4
    \$\begingroup\$ The spec is kinda poor. Please provide an exact definition of what it is supposed to do - an example implementation doesn't suffice. \$\endgroup\$ Aug 23, 2014 at 17:40
  • 1
    \$\begingroup\$ Is Timeago some new scripting language? Is updating every 30 seconds optional (as stated in one place) or a requirement (as stated in another)? What I/O mechanisms are acceptable? What rounding should be used? In particular, how does rounding interact with variable-length time periods such as calendar months and years? Some of these may imply follow-up questions depending on your answers. \$\endgroup\$ Aug 23, 2014 at 18:00
  • 1
    \$\begingroup\$ @Abdossam I know we all seem pretty fussy but it's because questions on this site are supposed to have objective winning criteria and a clear spec. \$\endgroup\$ Aug 23, 2014 at 19:22
  • 1
    \$\begingroup\$ Two suggestions: 1) Leave out the HTML part. I guess nobody want's to write an HTML parser before being able to tackle the real task of printing times. 2) Make clear that you restrict to "second(s)", "minute(s)", "hour(s)" and "day(s)". You might add "week(s)" if you wish. But months and years are not that clearly defined (28-31 days / 365 or 366 days...). This should fix the major concerns with this question in my point of view. \$\endgroup\$
    – Falko
    Aug 23, 2014 at 20:10

6 Answers 6


Ruby, 184 177

->n{x=Time.now.to_i-n;d=[3650*y=86400,365*y,7*y,y,3600,60,1];(0..6).map{|i|c=x/d[i];(x%=d[i]*c;"#{c} #{%w[decade year week day hour minute second][i]}#{c<2?'':'s'}")if c>0}*' '}

There's nothing particularly clever here, but I suspect it's still very close to optimal.

Example run

p ->n{x=Time.now.to_i-n;d=[3650*y=86400,365*y,7*y,y,3600,60,1];(0..6).map{|i|c=x/d[i];(x%=d[i]*c;"#{c} #{%w[decade year week day hour minute second][i]}#{c<2?'':'s'}")if c>0}*' '}[0]
"4 decades 4 years 41 weeks 3 days 14 hours 20 minutes 48 seconds"

J , 165

;' '&,@":&.>@((#~([:*&>{."1))@((;:' decades years weeks days hours minutes seconds')(],.([}.~[:-1=])&.>)<"0@(_ 10 52 7 24 60 60&#:)@(-~([:".@}:[:2!:0'date +%s'"_))))

Can probably be golfed more. Uses a shell call to date for getting the current unix epoch time, since Unix epoch is unavailable in J.

Example run:

;' '&,@":&.>@((#~([:*&>{."1))@((;:' decades years weeks days hours minutes seconds')(],.([}.~[:-1=])&.>)<"0@(_ 10 52 7 24 60 60&#:)@(-~([:".@}:[:2!:0'date +%s'"_)))) 0
4 decades 4 years 41 weeks 3 days 12 hours 54 minutes 1 second

Python - 183

import time;t=int(time.time()-input());d=86400
for f,u in zip((3650*d,365*d,7*d,d,3600,60,1),'decade year week day hour minute second'.split()):
 if t/f:print`t/f`,u+'s'*(t/f>1),;t%=f

Output for a timestamp 999996400 seconds in the past:

3 decades 1 year 37 weeks 46 minutes 39 seconds

JavaScript, 392

t=function(c){i=function(){var a=+new Date/1e3-c,b=document;29>a?b.write("just now"):60>a?b.write((a|0)+" seconds ago"):60<a&&120>a?b.write("1 minute ago"):60>a/60?b.write((a/60|0)+" minutes ago"):60<a/60&&120>a/60?b.write("1 hour ago"):24>a/3600?b.write((a/3600|0)+" hours ago"):24<a/3600&&48>a/3600?b.write("1 day ago"):1<=a/86400&&b.write((a/86400|0)+" days ago")};i();setInterval(i,3e4)};

Also the unminified code for the curious ones

t = function(timestamp){

i = function() {
var diff = (+new Date/1e3)-(timestamp),
d = document;

    if( (diff) < 29) {

        d.write( 'just now' )
    else if( diff < 60) {

        d.write( ( (diff) |0 ) + ' seconds ago' )
    else if( diff > 60 && diff < 120) {
        d.write(  '1 minute ago' )
    else if( (diff)/60 < 60) {
        d.write( ( (diff)/60 |0 ) + ' minutes ago' )
    else if( (diff)/60 > 60 && (diff)/60 < 120) {
        d.write( '1 hour ago' )
    else if( (diff)/3600 < 24) {
        d.write( ( (diff)/3600 |0 ) + ' hours ago' )
    else if( (diff)/3600 > 24 && (diff)/3600 < 48) {
        d.write( '1 day ago' )
    else if( (diff)/86400 >= 1) {
        d.write( ( (diff)/86400 |0 ) + ' days ago' )


setInterval(i, 3e4)


It updates every 30 seconds and calculates both singular and plural.

To run it use t(unix_timestamp)

  • \$\begingroup\$ Shouldn't you use fat arrow notation? \$\endgroup\$ Aug 24, 2014 at 20:20
  • \$\begingroup\$ @user965091 Please avoid throwing around accusations without any proof via public comments on unrelated posts; if you think someone is using a sock account, flag a post of theirs for moderator attention. I see absolutely no reason to suspect any sockpuppetry here, and even if there was, such a discussion should not be had in public. \$\endgroup\$
    – Doorknob
    Aug 30, 2014 at 19:08
  • \$\begingroup\$ @user965091 I don't see how any of the comments here could be considered "provocations." In any case, rudeness is not tolerated on the Stack Exchange network. Please try to remain courteous to all users, regardless of whether you suspect they are breaking the rules or for any other reason. \$\endgroup\$
    – Doorknob
    Aug 30, 2014 at 21:42

Javascript, 287

function p(e,n){return e>2?e+" "+n+"s ":e+" "+n+" "}function t(e){n=new Date/1e3,l=e-n,c=1,m=60,h=60*m,d=24*h,w=7*d,y=365*d,a=10*y,s="",v={a:"Decade",y:"Year",w:"Week",d:"Day",h:"Hour",m:"Minute",c:"Second"};for(i in v)k=v[i],i=window[i],(r=Math.floor(l/i))>0&&(s+=p(r,k)),l%=i;alert(s)}

to run use t(secondsInFuture);

  • 1
    \$\begingroup\$ When I run t(10) I just get an empty alert. \$\endgroup\$
    – Ingo Bürk
    Aug 24, 2014 at 12:11
  • \$\begingroup\$ Ugh, forgot the seconds, thanks @IngoBürk. To be clear its t(new Date()/1000 + 10); \$\endgroup\$
    – Victory
    Aug 24, 2014 at 21:13
  • \$\begingroup\$ Use ES6's fat arrow notation, also eval(i) is 2 bytes shorter than window[i]. \$\endgroup\$
    – Alexia
    Aug 25, 2014 at 17:17

Javascript, 263

i=[315360000,31536000,604800,86400,3600,60,1];s=['decade','year','week','day','hour','minute','second'];function g(d){return p(parseInt((new Date().getTime()-d)/1000), 0);}function p(d,n){k=d-d%i[n];r=k/i[n];return (r>0?r+' '+s[n]+'(s) ':'')+(n<6?p(d-k,n+1):'');}

to run from the Javascript console, call


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.