DEV Community

Cover image for Showing "time ago" in a Social Feed using Intl.RelativeTimeFormat
Mads Stoumann
Mads Stoumann

Posted on

Showing "time ago" in a Social Feed using Intl.RelativeTimeFormat

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;
}
Enter fullscreen mode Exit fullscreen mode

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));
Enter fullscreen mode Exit fullscreen mode

... returns "17 days ago".

Let's change the locale to German:

console.log(timeAgo(date1, 'de'));
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
grahamthedev profile image
GrahamTheDev

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. ❤️🦄

Collapse
 
madsstoumann profile image
Mads Stoumann

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.

Collapse
 
zachfotis profile image
Fotios Zachopoulos

Informative post! I like the approach! Thank you!