I'm currently implementing a Social Feed for a client, and had some issues with vulnerabilities in node_modules
and an old "time-ago"-library.
Inspecting the code, I could see, that the code took a Date
-object with .getTime()
, compared it with the current time — new Date().getTime()
— and then used a lot of code to return strings like "3 minutes ago", "2 days ago" etc.
Instead of finding another and newer "time-ago"-library, I decided to give it a go myself, and stumbled upon the RelativeTimeFormat
of the Intl-API — supported in all browsers except Internet Explorer.
These wonderful methods greatly simplifies the code needed for a "time-ago"-library, so I wrote this simple method:
function timeAgo (timestamp, locale = 'en') => {
let value;
const diff = (new Date().getTime() - timestamp.getTime()) / 1000;
const minutes = Math.floor(diff / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
const months = Math.floor(days / 30);
const years = Math.floor(months / 12);
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
if (years > 0) {
value = rtf.format(0 - years, "year");
} else if (months > 0) {
value = rtf.format(0 - months, "month");
} else if (days > 0) {
value = rtf.format(0 - days, "day");
} else if (hours > 0) {
value = rtf.format(0 - hours, "hour");
} else if (minutes > 0) {
value = rtf.format(0 - minutes, "minute");
} else {
value = rtf.format(0 - diff, "second");
}
return value;
}
It's 387 bytes minified, and just 244 bytes gzipped.
Testing it
I'm writing this on January 18th 2022, so this snippet:
const date1 = new Date('2022-01-01');
console.log(timeAgo(date1));
... returns "17 days ago".
Let's change the locale to German:
console.log(timeAgo(date1, 'de'));
This returns "vor 17 Tagen"´. With the locale fr
, it returns "il y a 17 jours".
Try it yourself with your own language-locale.
Now, let's try a timestamp, that is just a few minutes in the past (as of time of writing!):
const date1 = new Date('2022-01-18T08:30:00.000Z');
This returns "6 minutes ago" with an english locale.
If you just parse new Date()
, the string will be "now" with an english locale.
If your Date()
is in the future, it will be "[years|months|days|hours|minutes|seconds] from now".
Not all months are 30 days
Some of you might have wondered about this line of code:
const months = Math.floor(days / 30);
And yes, this is not super-accurate, but an average value.
If you have timelines with very old entries, you might want to add a bit more code to handle months
and years
!
Photo by KoolShooters from Pexels
Top comments (3)
Was just thinking I hadn’t seen a post from you in my notifications for a while.
Great post, I didn’t realise how much simpler the intl.relativetimeformat could make it, and I think your month approximation is fine for the intended use case. ❤️🦄
Thanks! Yes, it's been a while - hope you're doing fine, and all your plans are coming along! I am super-busy at the moment, but have a few articles lined up.
Informative post! I like the approach! Thank you!