Human-readable timestamps with Luxon

How to display something was posted “4 days ago”, now that Moment.js has become a legacy project to be avoided

The problem

You are building a feed and you want to display when its items were created. You want to present that in the format of “x time ago”. “7 minutes ago” is both friendlier and handier when it comes to feeds, over something like “20th of October” or “Oct 20th”.

However, the solution you may have used before and still dominates all search results is now a code smell: Moment.js is in maintenance mode and strongly advised against by various sources, including itself!

I’ve been experimenting with alternative third-party libraries, after promptly deciding Javascript’s Date is still too unpleasant for me to use out-of-the-box, with too many gotchas to worry about.

So I’ve been favouring Luxon, the alternative by a core Moment.js contributor, and I was googling my way to doing human-readable relative time with Luxon… and couldn’t find a decent result to save my life.

Even in their own their extensive docs, nothing relevant was matching “human” or even “ago”; turns out the magic word is actually “relative” and I decided to write the article that would have saved me some... absolute time. If you’re reading this, hopefully it’s saved you some 🙌🏽

nothing like saving time

The solution with Luxon

There are two common ways to store date & time information in Javascript / Typescript.

One is in Unix or Epoch time but in milliseconds. In which case your feed items would have a property like { createdAt: 1587546142000 }.

Let’s write a method that would take that timestamp and use Luxon to return that time relative to now:

import { DateTime } from 'luxon'

export const timestampToRelativeTime = (timestamp: number) =>
  DateTime.fromMillis(timestamp).toRelative()

The other common way to store date & time is as an ISO string, where your feed items would have a property like { createdAt: '2020-04-22T09:02:22.000Z' }.

Our method for taking a string like that and turning it into a human-readable “x time ago” is extremely similar:

import { DateTime } from 'luxon'

export const isoStringToRelativeTime = (isoString: string) =>
  DateTime.fromISO(isoString).toRelative()

If you do make it to the Luxon docs, the examples there are quite decent, showing you how to do things like localisation!

Whatever you do, my advice is to do extract a method for that toRelativeTime transformation. It’s the type of advice that is common in engineering, and for good reason!

In this case the benefit is you’d only need to change the internals of your abstraction if you ever wanted to switch out Luxon, instead of changing the implementation everywhere you’re showing a relative time.

Similarly, if you are using Moment.js directly and everywhere in your codebase, it’s a solid idea to abstract it away behind a method first, and then refactor to use something lighter and still heavily supported… like Luxon! Maybe even take inspiration from these tests 😄

The Demo

I built this blog with MDX, so might as well throw in an interactive demo:

1 day ago
16 days ago

Tapping around, you may notice that the relative times do not update as the seconds, minutes and days creep by… That’s because I’m waiting for you to tell me that’s something you want to see! Get in touch and I’ll happily implement for you 🚀

Check out all posts