Intl.RelativeTimeFormat

Published · Tagged with Intl

Modern web applications often use phrases like “yesterday”, “42 seconds ago”, or “in 3 months” instead of full dates and timestamps. Such relative time-formatted values have become so common that several popular libraries implement utility functions that format them in a localized manner. (Examples include Moment.js, an array of such language tags.

Here’s an example of using a different language (Spanish):

const rtf = new Intl.RelativeTimeFormat('es');

rtf.format(3.14, 'second');
/ → 'dentro de 3,14 segundos'

rtf.format(-15, 'minute');
/ → 'hace 15 minutos'

rtf.format(8, 'hour');
/ → 'dentro de 8 horas'

rtf.format(-2, 'day');
/ → 'hace 2 días'

rtf.format(3, 'week');
/ → 'dentro de 3 semanas'

rtf.format(-5, 'month');
/ → 'hace 5 meses'

rtf.format(2, 'quarter');
/ → 'dentro de 2 trimestres'

rtf.format(-42, 'year');
/ → 'hace 42 años'

Additionally, the Intl.RelativeTimeFormat constructor accepts an optional options argument, which gives fine-grained control over the output. To illustrate the flexibility, let’s look at some more English output based on the default settings:

/ Create a relative time formatter for the English language, using the
/ default settings (just like before). In this example, the default
/ values are explicitly passed in.
const rtf = new Intl.RelativeTimeFormat('en', {
localeMatcher: 'best fit', / other values: 'lookup'
style: 'long', / other values: 'short' or 'narrow'
numeric: 'always', / other values: 'auto'
});

/ Now, let’s try some special cases!

rtf.format(-1, 'day');
/ → '1 day ago'

rtf.format(0, 'day');
/ → 'in 0 days'

rtf.format(1, 'day');
/ → 'in 1 day'

rtf.format(-1, 'week');
/ → '1 week ago'

rtf.format(0, 'week');
/ → 'in 0 weeks'

rtf.format(1, 'week');
/ → 'in 1 week'

You may have noticed that the above formatter produced the string '1 day ago' instead of 'yesterday', and the slightly awkward 'in 0 weeks' instead of 'this week'. This happens because by default, the formatter uses the numeric value in the output.

To change this behavior, set the numeric option to 'auto' (instead of the implicit default of 'always'):

/ Create a relative time formatter for the English language that does
/ not always have to use numeric value in the output.
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

rtf.format(-1, 'day');
/ → 'yesterday'

rtf.format(0, 'day');
/ → 'today'

rtf.format(1, 'day');
/ → 'tomorrow'

rtf.format(-1, 'week');
/ → 'last week'

rtf.format(0, 'week');
/ → 'this week'

rtf.format(1, 'week');
/ → 'next week'

Analogous to other Intl classes, Intl.RelativeTimeFormat has a formatToParts method in addition to the format method. Although format covers the most common use case, formatToParts can be helpful if you need access to the individual parts of the generated output:

/ Create a relative time formatter for the English language that does
/ not always have to use numeric value in the output.
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

rtf.format(-1, 'day');
/ → 'yesterday'

rtf.formatToParts(-1, 'day');
/ → [{ type: 'literal', value: 'yesterday' }]

rtf.format(3, 'week');
/ → 'in 3 weeks'

rtf.formatToParts(3, 'week');
/ → [{ type: 'literal', value: 'in ' },
/ { type: 'integer', value: '3', unit: 'week' },
/ { type: 'literal', value: ' weeks' }]

For more information about the remaining options and their behavior, see Node.js: supported since version 12

  • Babel: no support
  • Follow Lee on X/Twitter - Father, Husband, Serial builder creating AI, crypto, games & web tools. We are friends :) AI Will Come To Life!

    Check out: eBank.nz (Art Generator) | Netwrck.com (AI Tools) | Text-Generator.io (AI API) | BitBank.nz (Crypto AI) | ReadingTime (Kids Reading) | RewordGame | BigMultiplayerChess | WebFiddle | How.nz | Helix AI Assistant