11
\$\begingroup\$

I wrote a little function which formats a ms timestamp in a human readable way. I know there are lots of scripts out there, but I needed a very simple one, which only outputs minutes and hours.

I was wondering if there is any way to shorten or improve this code snippet, because to me it seems to be very long for the few things it actually does.

function prettyTime(ms) {
      var sec = ms / 1000,
          time,
          timeUnit;

      if(sec > 3600) {
          // Hours
          time = Math.round(sec / 3600);
          timeUnit = ' hr';
      } else if(sec > 60) {
          // Minutes
          time = Math.round(sec / 60);
          timeUnit = ' min';
      } else {
          return 'less than 1 min';  
      }

      if(time > 1) {
          timeUnit += 's';   
      }

      return 'about ' + time + timeUnit + 'ago';
}

alert(prettyTime(7600001));
\$\endgroup\$
1

1 Answer 1

9
\$\begingroup\$

Hope this might be helpful -

function getRelativeTime(ms){
    var SECOND_MS = 1000;
    var MINUTE_MS = 60 * SECOND_MS;
    var HOUR_MS = 60 * MINUTE_MS;
    var DAY_MS = 24 * HOUR_MS;
    var WEEK_MS = 7 * DAY_MS;
    var MONTH_MS = 30 * DAY_MS;

    var lookup = ["months", "weeks", "days", "hours", "minutes", "seconds"];
    var values = [];
    values.push(ms / MONTH_MS); ms %= MONTH_MS;
    values.push(ms / WEEK_MS); ms %= WEEK_MS;
    values.push(ms / DAY_MS); ms %= DAY_MS;
    values.push(ms / HOUR_MS); ms %= HOUR_MS;
    values.push(ms / MINUTE_MS); ms %= MINUTE_MS;
    values.push(ms / SECOND_MS); ms %= SECOND_MS;

    var pretty = "about "; 
    for(var i=0 ; i <values.length; i++){
        var val = Math.round(values[i]);
        if(val <= 0) continue;

        pretty += val + " " + lookup[i] + " ago";
        break;
    }
    return pretty;
}


getRelativeTime(10000);

Output :

about 10 seconds ago

You can easily customize above code for your "xx hours and xx mins ago" use-case. Just change the for loop like this -

for(var i=0 ; i <values.length; i++){
    var val = Math.round(values[i]);
    if(val <= 0) continue;

    pretty += val + " " + lookup[i];

    var nextval = Math.round(values[i+1]);
    if(i+1 < values.length && nextval > 0){
      pretty += " and " + nextval + " " + lookup[i+1] + " ago";
    }
    else {
      pretty += " ago";
    }
    break;
}

Output

getRelativeTime(100000);

about 2 minutes and 40 seconds ago

getRelativeTime(1000000);

about 17 minutes and 40 seconds ago

UPDATE:

Math.round is causing wrong result in above code, Math.floor is more appropriate.

\$\endgroup\$
4
  • \$\begingroup\$ Thanks, that looks a lot cleaner to me, although I think var SECOND = 1; should be var SECOND = 1000;, shouldn't it? Is there any elegant way to use 'less than a minute ago' instead of seconds? \$\endgroup\$
    – mrksbnch
    Commented Mar 17, 2014 at 23:48
  • \$\begingroup\$ You're right, updated the code. \$\endgroup\$
    – Kevindra
    Commented Mar 17, 2014 at 23:54
  • 3
    \$\begingroup\$ IMO, SECOND, MINUTE, etc. should be named SECOND_MS, MINUTE_MS, and so on so it's clear what units they're in. \$\endgroup\$
    – jamesdlin
    Commented Mar 18, 2014 at 1:37
  • \$\begingroup\$ Makes sense, you got it! \$\endgroup\$
    – Kevindra
    Commented Mar 18, 2014 at 20:14

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