Format Dates with JavaScript Intl DateTimeFormat

The Intl.DateTimeFormat object is a built-in JavaScript API that provides language-sensitive date and time formatting without the need for external libraries. This article explains how Intl.DateTimeFormat works, how it resolves locale conventions, and how you can configure options to control components, time zones, and calendars.

Basic Syntax and Mechanism

The Intl.DateTimeFormat constructor takes two optional arguments: a locale identifier (or array of identifiers) and an options object. It compiles an internal formatter tailored to the specified locale’s conventions.

const date = new Date('2025-05-15T14:30:00Z');

// Format using US English conventions (MM/DD/YYYY)
const usFormatter = new Intl.DateTimeFormat('en-US');
console.log(usFormatter.format(date)); // "5/15/2025"

// Format using German conventions (DD.MM.YYYY)
const deFormatter = new Intl.DateTimeFormat('de-DE');
console.log(deFormatter.format(date)); // "15.5.2025"

When you omit the locale parameter or pass undefined, JavaScript uses the runtime’s default locale (usually the browser or operating system setting).

Specifying Locales

Locales are defined using standard BCP 47 language tags (such as en-US, fr-CA, ja-JP, or ar-EG). You can also pass an array of locales to establish a fallback hierarchy:

// Tries Breton first; if unsupported, falls back to French, then default
const formatter = new Intl.DateTimeFormat(['br', 'fr']);

Locales can include Unicode extension keys to specify preferences like calendar types or numbering systems:

// Format using the Japanese imperial calendar
const jpCalendar = new Intl.DateTimeFormat('ja-JP-u-ca-japanese');
console.log(jpCalendar.format(date)); // "R7/5/15" (Reiwa 7)

Using dateStyle and timeStyle

The modern Intl.DateTimeFormat API provides high-level convenience properties: dateStyle and timeStyle. They accept "full", "long", "medium", or "short".

const fullFormat = new Intl.DateTimeFormat('en-GB', {
  dateStyle: 'full',
  timeStyle: 'short'
});

console.log(fullFormat.format(date));
// "Thursday, 15 May 2025 at 15:30"

Granular Formatting Options

When predefined styles do not fit your requirements, you can customize individual date and time tokens:

const customFormatter = new Intl.DateTimeFormat('es-ES', {
  weekday: 'long',
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  hour: '2-digit',
  minute: '2-digit',
  hour12: false
});

console.log(customFormatter.format(date));
// "jueves, 15 de mayo de 2025, 16:30"

Time Zone Handling

By default, dates are formatted in the user’s local time zone. You can explicitly set a target time zone using IANA time zone identifiers (such as "UTC", "America/New_York", or "Asia/Tokyo").

const nyFormatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'America/New_York',
  timeZoneName: 'short',
  timeStyle: 'long'
});

console.log(nyFormatter.format(date));
// "10:30:00 AM EDT"

Custom Layouts with formatToParts()

If you need to render localized date tokens inside custom HTML markup or non-standard layouts, use formatToParts(). This method returns an array of objects containing the token type and value.

const formatter = new Intl.DateTimeFormat('en-US', { month: 'short', day: 'numeric' });
const parts = formatter.formatToParts(date);

console.log(parts);
// [
//   { type: 'month', value: 'May' },
//   { type: 'literal', value: ' ' },
//   { type: 'day', value: '15' }
// ]

Performance Advantage

Creating an Intl.DateTimeFormat instance is computationally heavier than formatting a single string. When formatting multiple dates with the same configuration, create a single instance and call .format() repeatedly rather than using Date.prototype.toLocaleDateString(), which reconstructs the internal formatter on every call.