views:

981

answers:

3

Let's say I've got two strings in JavaScript:

var date1 = '2008-10-03T20:24Z'
var date2 = '2008-10-04T12:24Z'

How would I come to a result like so:

'4 weeks ago'

or

'in about 15 minutes'

(should support past and future).

There are solutions out there for the past diffs, but I've yet to find one with support for future time diffs as well.

These are the solutions I tried:

John Resig's Pretty Date and Zach Leatherman's modification

Bonus points for a jQuery solution.

+5  A: 

Looking at the solutions you linked... it is actually as simple as my frivolous comment!

Here's a version of the Zach Leatherman code that prepends "In " for future dates for you. As you can see, the changes are very minor.

  function humane_date(date_str){
      var time_formats = [
       [60, 'Just Now'],
       [90, '1 Minute'], // 60*1.5
       [3600, 'Minutes', 60], // 60*60, 60
       [5400, '1 Hour'], // 60*60*1.5
       [86400, 'Hours', 3600], // 60*60*24, 60*60
       [129600, '1 Day'], // 60*60*24*1.5
       [604800, 'Days', 86400], // 60*60*24*7, 60*60*24
       [907200, '1 Week'], // 60*60*24*7*1.5
       [2628000, 'Weeks', 604800], // 60*60*24*(365/12), 60*60*24*7
       [3942000, '1 Month'], // 60*60*24*(365/12)*1.5
       [31536000, 'Months', 2628000], // 60*60*24*365, 60*60*24*(365/12)
       [47304000, '1 Year'], // 60*60*24*365*1.5
       [3153600000, 'Years', 31536000], // 60*60*24*365*100, 60*60*24*365
       [4730400000, '1 Century'], // 60*60*24*365*100*1.5
      ];

      var time = ('' + date_str).replace(/-/g,"/").replace(/[TZ]/g," "),
       dt = new Date,
       seconds = ((dt - new Date(time) + (dt.getTimezoneOffset() * 60000)) / 1000),
       token = ' Ago',
          prepend = '',
       i = 0,
       format;

      if (seconds < 0) {
       seconds = Math.abs(seconds);
       token = '';
          prepend = 'In ';
      }

      while (format = time_formats[i++]) {
       if (seconds < format[0]) {
        if (format.length == 2) {
         return (i>1?prepend:'') + format[1] + (i > 1 ? token : ''); // Conditional so we don't return Just Now Ago
        } else {
         return prepend + Math.round(seconds / format[2]) + ' ' + format[1] + (i > 1 ? token : '');
        }
       }
      }

      // overflow for centuries
      if(seconds > 4730400000)
       return Math.round(seconds / 4730400000) + ' Centuries' + token;

      return date_str;
  };
moonshadow
My brain is slow. Thanks! :)
Nick Sergeant
A: 

Heh - I actually wrote a function to do this exact thing yesterday (and it's not on this computer so I'll just have to try to remember it)

I extended the Date prototype class, but this could quite easily just be put into a regular function.

Date.prototype.toRelativeTime = function(otherTime) {
    // if no parameter is passed, use the current date.
    if (otherTime == undefined) otherTime = new Date();

    var diff = Math.abs(this.getTime() - otherTime.getTime()) / 1000;

    var MIN = 60,        // some "constants" just 
        HOUR = 3600,     // for legibility
        DAY = 86400
    ;
    var out, temp;
    if (diff < MIN) {
        out = "Less than a minute";

    } else if (diff < 15 * MIN) {
        // less than fifteen minutes, show how many minutes
        temp = Math.round(diff / MIN);
        out = temp + " minute" + (temp == 1 ? "" : "s");
        // eg: 12 minutes
    } else if (diff < HOUR) {
        // less than an hour, round down to the nearest 5 minutes
        out = (Math.floor(diff / (5 * MIN)) * 5) + " minutes";
    } else if (diff < DAY) {
        // less than a day, just show hours
        temp = Math.round(diff / HOUR);
        out = temp + " hour" + (temp == 1 ? "" : "s");
    } else if (diff < 30 * DAY) {
        // show how many days ago
        temp = Math.round(diff / DAY);
        out = temp + " day" + (temp == 1 ? "" : "s");
    } else if (diff < 90 * DAY) {
        // more than 30 days, but less than 3 months, show the day and month
        return this.getDate() + " " + this.getShortMonth();  // see below
    } else {
        // more than three months difference, better show the year too
        return this.getDate() + " " + this.getShortMonth() + " " + this.getFullYear();
    }
    return out + (this.getTime() > otherTime.getTime() ? " from now" : " ago");

};

Date.prototype.getShortMonth = function() {
    return ["Jan", "Feb", "Mar",
            "Apr", "May", "Jun",
            "Jul", "Aug", "Sep",
            "Oct", "Nov", "Dec"][this.getMonth()];
};

// sample usage:
var x = new Date(2008, 9, 4, 17, 0, 0);
alert(x.toRelativeTime());    // 9 minutes from now

x = new Date(2008, 9, 4, 16, 45, 0, 0);
alert(x.toRelativeTime());    // 6 minutes ago

x = new Date(2008, 11, 1);    // 1 Dec

x = new Date(2009, 11, 1);    // 1 Dec 2009
nickf
A: 

Call me crazy, but I was thinking regular expressions (there is a site that does what you're asking, I just can't find it now).

keif