Format "5 days ago" localized relative date strings in a few lines with native JavaScript
The native Intl.RelativeTimeFormat API can generate nicely formatted relative date/time strings without any external dependencies.
The internationalization API in browsers has improved a lot in the last few years. This is the first blog post in a series that will show neat little examples that will help you get familiar with the native Intl APIs.
This post will bring up the basics of using the Intl.RelativeTimeFormat
constructor for format dates into strings in the popular "5 days ago" used in various services over the internet.
Calculate the delta days
First, we need to calculate how many days have passed since the date, or how many days are left until the date.
This can be done by just subtracting the timestamp of the given date from the timestamp of now.
const date = new Date('2021-02-10');
// Subtract the date with the current, divide to get number of days
const deltaDays = (date.getTime() - Date.now()) / (1000 * 3600 * 24);
(the result would be in milliseconds, to transform into days we need to divide by milliseconds per second, seconds per hour, hours per day, (1000 * 3600 * 24))
Format into a relative date string
Now we can use an Intl.RelativeTimeFormat
instance to format our variable deltaDays
. As we only want whole days in the result we need to round off deltaDays
before formatting.
// Create relative time formatter, if a locale string argument (e.g. 'sv-SE') is
// supplied that locale will be used instead of the browsers selected language
const formatter = new Intl.RelativeTimeFormat();
// Format days to string (rember to round off deltaDays)
const result = formatter.format(Math.round(deltaDays), 'days');
console.log(result);
// Output: 17 days ago
One of the neat features of Intl.RelativeTimeFormat
is that it will default to the language the browser runs in and automatically translate the words to that language. If you rather want to lock the translation into a language that the rest of your service uses, just pass that locale as the first argument the the Intl.RelativeTimeFormat
constructor like so:
const formatter = new Intl.RelativeTimeFormat('en-US');
When running formatter.format
we must also pass in that we want to format our Number
into days rather than minutes, hours, and so on (e.g. formatter.format(10, 'days')
).
Create a reusable function
Let's rewrite this into a reusable function that will also have an optional locale argument so that it's possible to lock the formatting into a specific locale.
Another small trick here is that the Date
constructor can be wrapped into another Date
constructor (new Date(new Date())
), because of this we can add this wrapping to the first argument to allow the function to accept millisecond timestamps, ISO 8601 strings as well as Date
instances.
function formatDaysAgo(value, locale) {
const date = new Date(value);
const deltaDays = (date.getTime() - Date.now()) / (1000 * 3600 * 24);
const formatter = new Intl.RelativeTimeFormat(locale);
return formatter.format(Math.round(deltaDays), 'days');
}
Example usage:
console.log(formatDaysAgo(new Date('2021-02-10')));
// 17 days ago
console.log(formatDaysAgo(Date.now()));
// in 0 days
console.log(formatDaysAgo('2021-03-13'));
// in 14 days
console.log(formatDaysAgo('2021-03-13', 'sv-SE'));
// om 14 dagar
More information
The Intl.RelativeTimeFormat
API provides several more configuration options, you can read more about them at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat .
Happy coding!