Relative times
Tags: relativetimeformat, timestamps, relative, times
Published: 2023-09-13 14:34:23

---
title: Relative times
published: true
date: 2023-08-07 10:43:20 UTC
tags: relativetimeformat,timestamps,relative,times
canonical_url: https://adactio.com/journal/20377
---

Last week [Phil](https://www.gyford.com/) posted [a little update](https://mastodon.social/@OohDirectory/110825402413538818) about his excellent site, [ooh.directory](https://ooh.directory/):

> If you’re in the habit of visiting the Recently Updated Blogs page, and leaving it open, the times when each blog was updated will now keep up with the relentless passing of time.
> 
> Does that make sense? “3 minutes ago” will change to “4 minutes ago” and so on and on and on, until you refresh the page.

I thought that was a nice little addition, and I immediately thought of [The Session](https://thesession.org). There are `time` elements all over the site with relative times as the text content: 2 minutes ago, 7 hours ago, 1 year ago, and so on. Those strings of text are generated on the server. But I figured it would be nice enhancement to periodically update them in the browser after the page has loaded.

I viewed source to see how Phil was doing it. The code is nice and short, using a library called [Day.js](https://day.js.org/en/) with a plug-in for relative time.

“Hang on”, I thought, “isn’t there some web standard for doing this kind of thing?” I had a vague memory of some JavaScript API for formatting dates and times.

Sure enough, we’ve now got the [`Intl.RelativeTimeFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/Intl.RelativeTimeFormat) object. It’s got [browser support across the board](https://caniuse.com/mdn-javascript_builtins_intl_relativetimeformat).

[Here’s the code I wrote](https://gist.github.com/adactio/ccca5710152e77fb26b4a4df0ea8fc1e).

I’ve got a function that loops through all the `time` elements with `datetime` attributes. It compares the current timestamp to that value to get the elapsed time. Then that’s formatted using the `format()` method and output as `innerText`.

You need to tell the `format()` method which units you want to use: seconds, minutes, hours, days, etc. So there’s a little bit of looping to figure out which unit is most appropriate. If the elapsed time is less than a minute, use seconds. If the elapsed time is less than an hour, use minutes. If the elapsed time is less than a day, use hours. You get the idea.

It’s a pity there isn’t some kind of magic unit like “auto” to do this, but it’s not much extra code to figure it out.

Anyway, that function runs periodically using `setInterval()`. I’ve set it to run every 30 seconds in [my gist](https://gist.github.com/adactio/ccca5710152e77fb26b4a4df0ea8fc1e). On [The Session](https://thesession.org/) I’ve set it to one minute.

You’ll notice that I’m grabbing all the relevant `time` elements—using `document.querySelector('time[datetime]')`—every time the function is run. That may seem inefficient. Couldn’t I just grab them once and then keep them stored as an array? But I want this to work even if the page contents have been updated with Ajax. (Do people even say “Ajax” any more? Get off my lawn, you pesky kids!)

I think I’ve written [this code](https://gist.github.com/adactio/ccca5710152e77fb26b4a4df0ea8fc1e) in an abstract way so that you should be able to drop it into any web page. For the calculations to work, you’ll need to either make sure that your `datetime` attributes are using timezones. Or, if there’s no timezone info, UTC is assumed.

This was a fun little piece of functionality to play around with. Now I know a little more about this `Intl.RelativeTimeFormat` object. The way I’m using it as a classic example of progressive enhancement. If a browser doesn’t support it, or if my code breaks, it’s no big deal. The funtionality is a little bonus that almost nobody will notice anyway. Just a small delighter …if you’re the kind of person who finds it delightful when relative time strings automatically update.

<script src="https://gist.github.com/adactio/ccca5710152e77fb26b4a4df0ea8fc1e.js"></script>