Formatting dates in JavaScript with Intl.DateTimeFormat

Date formatting in JavaScript can get trick to say the least. Let's see how Intl.DateTimeFormat can help.

Formatting dates in JavaScript with Intl.DateTimeFormat

What is Intl?

The Intl object in JavaScript is the home for methods and constructors of the ECMAScript Internationalization API. This API has a number of convenient features for converting strings, numbers, and dates.

Intl.DateTimeFormat is part of Intl and in this post we'll see how it can help with date formatting.

A quick introduction to ISO strings

Consider an ISO string like this:

const date = new Date().toISOString();

// "2020-02-05T16:30:41.392Z"

The ISO string format is convenient and can be used in the time HTML tag for example:

<time datetime="2020-02-05T16:30:41.392Z">Published on ...</time>

Or in the head:

<meta property="article:published_time" content="2020-02-05T16:30:41.392Z">

Search engines may consume these tags for displaying dates in the SERP. ISO strings are convenient for machines, but how about users? It can get tricky to convert between different time formats depending on the locale of the user.

Let's say we want to display a different time format for italian users ...

<time datetime="2020-02-05T16:30:41.392Z">Pubblicato il 05 Febbraio 2020</time>

and the american format for american users:

<time datetime="2020-02-05T16:30:41.392Z">Published on February 05, 2020</time>

What's the easiest way for converting between the two?

Formatting dates in JavaScript with Intl.DateTimeFormat

Intl.DateTimeFormat can help with the format() method which takes the date and converts depending on the locale supplied as the argument to Intl.DateTimeFormat.

Let's see a simple example with "vanilla" JavaScript. Here's an HTML document:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Formatting dates in JavaScript with Intl.DateTimeFormat</title>
</head>
<body>
    <!-- append the time here -->
</body>
<script src="datetime.js"></script>
</html>

And here's the JavaScript code in datetime.js for generating the date inside a time tag:

const isoString = new Date().toISOString();

const time = document.createElement("time");
time.setAttribute("datetime", isoString);
// forgive me father for I have sinned with innerText!
time.innerText = `Published on`;

document.body.appendChild(time);

This code will produce a time tag with an ISO string, the text "Published on" and nothing more. But we can use Intl.DateTimeFormat with the appropriate locale for converting to an american date:

const options = { month: "long", day: "numeric", year: "numeric" };
const date = new Date(isoString);
const americanDate = new Intl.DateTimeFormat("en-US", options).format(date);

Intl.DateTimeFormat takes a target locale and an object with formatting options. The format() methods takes a date object. Here's the complete code:

// imagine you've got the ISO string from the system
const isoString = new Date().toISOString();

const options = { month: "long", day: "numeric", year: "numeric" };
const date = new Date(isoString);
const americanDate = new Intl.DateTimeFormat("en-US", options).format(date);

const time = document.createElement("time");
time.setAttribute("datetime", isoString);
// forgive me father for I have sinned with innerText!
time.innerText = `Published on ${americanDate}`;

document.body.appendChild(time);

This snippet will produce the desired result:

Intl.DateTimeFormat

And to make your italian friends happy you can extract an utility function for converting to the appropriate (or to any other) date:

function ISOtoLongDate(isoString, locale = "en-US") {
  const options = { month: "long", day: "numeric", year: "numeric" };
  const date = new Date(isoString);
  const longDate = new Intl.DateTimeFormat(locale, options).format(date);
  return longDate;
}

Here's the function in action:

const isoString = new Date().toISOString();

function ISOtoLongDate(isoString, locale = "en-US") {
  const options = { month: "long", day: "numeric", year: "numeric" };
  const date = new Date(isoString);
  const longDate = new Intl.DateTimeFormat(locale, options).format(date);
  return longDate;
}

const italianDate = ISOtoLongDate(isoString, "it-IT");

const time = document.createElement("time");
time.setAttribute("datetime", isoString);
// forgive me father for I have sinned with innerText!
time.innerText = `Pubblicato il ${italianDate}`;

document.body.appendChild(time);

with its output:

Intl.DateTimeFormat italian

To learn more about Intl.DateTimeFormat check out the documentation on MDN.

toLocaleDateString or Intl.DateTimeFormat?

You may have noticed that toLocaleDateString give the same result of Intl.DateTimeFormat. You could do:

const options = { month: "long", day: "numeric", year: "numeric" };
const longDate = new Date().toLocaleDateString(locale, options);

So, which one should we use? Long story short, performance-wise Intl.DateTimeFormat is a safer choice.

Worth noting, format() returns the current date when called without arguments:

const options = { month: "long", day: "numeric", year: "numeric" };
new Intl.DateTimeFormat("en-US", options).format();

// "February 6, 2020"

Note: Date constructor in browsers and Node.js

new Date() returns shows a date like "Wed Feb 05 2020 18:46:03 GMT+0100 (Central European Standard Time)" when called in a browser. The same constructor call in Node.js returns shows an ISO string instead: "2020-02-05T17:47:03.065Z".

As pointed out by a fellow reader on Reddit the constructor returns the same date object in both browsers and Node.js. What's different is just the representation of the date in Node.js.

Thanks for reading!

Valentino Gagliardi

Hi! I'm Valentino! I'm a freelance consultant with a wealth of experience in the IT industry. I spent the last years as a frontend consultant, providing advice and help, coaching and training on JavaScript, testing, and software development. Let's get in touch!