javascript - lightweight - native js library




Javascript library for human-friendly relative date formatting (5)

I'd like to display some dates as relative to the current date in a human-friendly format.

Examples of human-friendly relative dates:

  • 10 seconds ago
  • 20 minutes from now
  • 1 day ago
  • 5 weeks ago
  • 2 months ago

Basically faithfully preserving the highest order of magnitude (and by preference, only shifting up units when passing 2 of those units - 5 weeks instead of 1 month).

Though I could live with a library that had less control and even more friendly dates like:

  • yesterday
  • tomorrow
  • last week
  • a few minutes ago
  • in a couple hours

Any popular libraries for this?


sugar.js has great date formatting functions.

Not only that, it also provides common general purpose functions like string formatting, number formatting, etc. that are convenient to use.


Here's something from the John Resig - http://ejohn.org/blog/javascript-pretty-date/

EDIT (6/27/2014): Following up on the comment from Sumurai8 - though the linked page still works, here is the excerpt for the pretty.js linked to from the article above:

pretty.js

/*
 * JavaScript Pretty Date
 * Copyright (c) 2011 John Resig (ejohn.org)
 * Licensed under the MIT and GPL licenses.
 */

// Takes an ISO time and returns a string representing how
// long ago the date represents.
function prettyDate(time) {
    var date = new Date((time || "").replace(/-/g, "/").replace(/[TZ]/g, " ")),
        diff = (((new Date()).getTime() - date.getTime()) / 1000),
        day_diff = Math.floor(diff / 86400);

    if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31) return;

    return day_diff == 0 && (
    diff < 60 && "just now" || diff < 120 && "1 minute ago" || diff < 3600 && Math.floor(diff / 60) + " minutes ago" || diff < 7200 && "1 hour ago" || diff < 86400 && Math.floor(diff / 3600) + " hours ago") || day_diff == 1 && "Yesterday" || day_diff < 7 && day_diff + " days ago" || day_diff < 31 && Math.ceil(day_diff / 7) + " weeks ago";
}

// If jQuery is included in the page, adds a jQuery plugin to handle it as well
if (typeof jQuery != "undefined") jQuery.fn.prettyDate = function() {
    return this.each(function() {
        var date = prettyDate(this.title);
        if (date) jQuery(this).text(date);
    });
};

Usage:

prettyDate("2008-01-28T20:24:17Z") // => "2 hours ago"
prettyDate("2008-01-27T22:24:17Z") // => "Yesterday"
prettyDate("2008-01-26T22:24:17Z") // => "2 days ago"
prettyDate("2008-01-14T22:24:17Z") // => "2 weeks ago"
prettyDate("2007-12-15T22:24:17Z") // => undefined

Excerpt from the article on usage:

Example Usage

In the following examples I make all the anchors on the site, that have a title with a date in it, have a pretty date as their inner text. Additionally, I continue to update the links every 5 seconds after the page has loaded.

With JavaScript:

function prettyLinks(){
    var links = document.getElementsByTagName("a");
    for ( var i = 0; i < links.length; i++ )
        if ( links[i].title ) {
            var date = prettyDate(links[i].title);
            if ( date )
                links[i].innerHTML = date;
        }
}
prettyLinks();
setInterval(prettyLinks, 5000);

With jQuery:

$("a").prettyDate();
setInterval(function(){ $("a").prettyDate(); }, 5000);

Faiz: Made some changes to the original code, bug fixes and improvements.

function prettyDate(time) {
    var date = new Date((time || "").replace(/-/g, "/").replace(/[TZ]/g, " ")),
        diff = (((new Date()).getTime() - date.getTime()) / 1000),
        day_diff = Math.floor(diff / 86400);
    var year = date.getFullYear(),
        month = date.getMonth()+1,
        day = date.getDate();

    if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31)
        return (
            year.toString()+'-'
            +((month<10) ? '0'+month.toString() : month.toString())+'-'
            +((day<10) ? '0'+day.toString() : day.toString())
        );

    var r =
    ( 
        (
            day_diff == 0 && 
            (
                (diff < 60 && "just now")
                || (diff < 120 && "1 minute ago")
                || (diff < 3600 && Math.floor(diff / 60) + " minutes ago")
                || (diff < 7200 && "1 hour ago")
                || (diff < 86400 && Math.floor(diff / 3600) + " hours ago")
            )
        )
        || (day_diff == 1 && "Yesterday")
        || (day_diff < 7 && day_diff + " days ago")
        || (day_diff < 31 && Math.ceil(day_diff / 7) + " weeks ago")
    );
    return r;
}

Since I wrote this answer, a well known library available is moment.js.


There are libraries available, but it is trivial to implement it yourself. Just use a handful of conditions.

Assume date is an instantiated Date object for the time you want to make a comparison against.

// Make a fuzzy time
var delta = Math.round((+new Date - date) / 1000);

var minute = 60,
    hour = minute * 60,
    day = hour * 24,
    week = day * 7;

var fuzzy;

if (delta < 30) {
    fuzzy = 'just then.';
} else if (delta < minute) {
    fuzzy = delta + ' seconds ago.';
} else if (delta < 2 * minute) {
    fuzzy = 'a minute ago.'
} else if (delta < hour) {
    fuzzy = Math.floor(delta / minute) + ' minutes ago.';
} else if (Math.floor(delta / hour) == 1) {
    fuzzy = '1 hour ago.'
} else if (delta < day) {
    fuzzy = Math.floor(delta / hour) + ' hours ago.';
} else if (delta < day * 2) {
    fuzzy = 'yesterday';
}

You would need to adapt this to handle future dates.


Sounds like you could use http://www.datejs.com/

They have an example on the main page that does exactly what you're describing!

EDIT: Actually, I think I reversed your question in my head. In any case, I think you could check it out as it's a really great library anyway!

EDIT x2: I'm going to echo what the others have said http://momentjs.com/ is probably the best choice available right now.

EDIT x3: I haven't used date.js in over a year. I'm exclusively using momentjs for all my date related needs.


here an example of sugar vs moment: for a calendar that displays weeks, I needed the last monday value:

moment.js

var m = moment().subtract("days", 1).sod().day(1) // returns a "moment"

sugar.js

var d = Date.past("monday") // returns a js Date object

I much prefer sugar and after some months with moment.js now switch to sugar.js. it is clearer and integrates nicely with Javascripts' Date class.

OP cases are covered by both libs, for sugar.js see http://sugarjs.com/dates





relative