DEV Community

Cover image for You're installing date-fns for 'X hours ago'. `Intl.RelativeTimeFormat` does it natively.
Parsa Jiravand
Parsa Jiravand

Posted on Edited on Originally published at bestpractic.org

You're installing date-fns for 'X hours ago'. `Intl.RelativeTimeFormat` does it natively.

When a comment timestamp reads "3 hours ago" instead of a raw ISO string, users stay oriented without thinking about it. Most teams reach for date-fns/formatDistanceToNow or moment().fromNow() to get there. Both pull in a full library for something the browser can do natively — and has been able to do since 2020.

The API

const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

rtf.format(-3, 'hour');   // "3 hours ago"
rtf.format(1, 'day');     // "tomorrow"
rtf.format(-1, 'day');    // "yesterday"
rtf.format(-2, 'week');   // "2 weeks ago"
rtf.format(3, 'month');   // "in 3 months"
Enter fullscreen mode Exit fullscreen mode

Two arguments: a number (negative = past, positive = future) and a unit string. The constructor takes a locale identifier and an options object. That's the whole surface area.

The numeric: 'auto' option

The second constructor argument controls whether you get "1 day ago" or "yesterday". With numeric: 'always' (the default), every value is formatted as a number. With numeric: 'auto', the formatter substitutes natural language when it's available for that locale:

const always = new Intl.RelativeTimeFormat('en', { numeric: 'always' });
const auto   = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

always.format(-1, 'day');  // "1 day ago"
auto.format(-1, 'day');    // "yesterday"

always.format(0, 'day');