JavaScript <time> to time ago / future
A small JS library to convert HTML 5 <time>
tags to an x time ago / in future.
For example:
<time datetime="2016-08-03">3 Aug 2016</time>
Will be displayed as instead of .
Why re-invent the wheel? The only JS libraries I could find were either jQuery based (I’m not using jQuery so don’t want the extra bloat) or did far more than I actually wanted. So I decided to create this one.
Date parsing
The hardest part is parsing the date. According to the HTML5 W3 spec the <time>
tag’s datetime
attribute should be in RFC 3339 format. The RFC 3339 is a subset of ISO 8601 with the exception that it allows -00:00
timezones.
The Date.parse
method will parse a subset of ISO 8601 which, as far as I can tell, covers all the RFC 3339 subset. So by removing any trailing -00:00
we should be able to parse any RFC 3339 date:
var date = Date.parse(dateTime.replace(/\-00:?00$/, ""));
Browser support
This works in Chrome, Firefox, Safari, Opera, IE 9+ and Edge.
In IE < 9 the Date.parse method doesn’t support ISO 8601. You could add a polyfill for it but, for my purposes, I decided to just let IE < 9 fallback to the default date instead.
Source Code
/**
* Take an RFC 3339 or ISO 8601 date and returns
* the date in human readable form.
*
* Will return undefined if lacks browser support
* or it cannot parse the date.
*
* @param {string} time
* @param {object} [lang] Optional language object
* @return {string|undefined}
* @license MIT
* @author Sam Clarke <sam@samclarke.com>
*/
function timeToWords(time, lang) {
lang = lang || {
postfixes: {
"<": " ago",
">": " from now",
},
1000: {
singular: "a few moments",
plural: "a few moments",
},
60000: {
singular: "about a minute",
plural: "# minutes",
},
3600000: {
singular: "about an hour",
plural: "# hours",
},
86400000: {
singular: "a day",
plural: "# days",
},
31540000000: {
singular: "a year",
plural: "# years",
},
};
var timespans = [1000, 60000, 3600000, 86400000, 31540000000];
var parsedTime = Date.parse(time.replace(/\-00:?00$/, ""));
if (parsedTime && Date.now) {
var timeAgo = parsedTime - Date.now();
var diff = Math.abs(timeAgo);
var postfix = lang.postfixes[timeAgo < 0 ? "<" : ">"];
var timespan = timespans[0];
for (var i = 1; i < timespans.length; i++) {
if (diff > timespans[i]) {
timespan = timespans[i];
}
}
var n = Math.round(diff / timespan);
return (
lang[timespan][n > 1 ? "plural" : "singular"].replace("#", n) + postfix
);
}
}
Example usage
document.addEventListener("DOMContentLoaded", function () {
var elements = document.getElementsByTagName("time");
for (var i = 0; i < elements.length; i++) {
var elm = elements[i];
// The date should be either in the datetime attribute
// or in the text contents if no datetime attribute
var date = elm.getAttribute("datetime") || elm.textContent;
var dateInWords = timeToWords(date);
if (dateInWords) {
elm.textContent = dateInWords;
}
// you could use setInterval to automatically update
// the timestamps every so often if wanted
}
});
The timeToWords
function also accepts a language object so the output can be translated. For example:
var norwegian = {
// Postfixes - ago / from now
postfixes: {
"<": " siden",
">": " fra nå",
},
// Seconds
1000: {
singular: "et øyeblikk",
plural: "et øyeblikk",
},
// Minutes
60000: {
singular: "omtrent et minutt",
plural: "# minutter",
},
// Hours
3600000: {
singular: "omtrent en time",
plural: "# timer",
},
// Days
86400000: {
singular: "en dag",
plural: "# dager",
},
// Years
31540000000: {
singular: "et år",
plural: "# år",
},
};
// Will set dateInWords to a Norwegian translation
var dateInWords = timeToWords(date, norwegian);
Comments