Intl.DateTimeFormat and DateTime Localization Formatting in JavaScript

Intl.DateTimeFormat and DateTime Localization Formatting in JavaScript

Description

Intl.DateTimeFormat is part of the JavaScript Internationalization API (Intl) and is used to format and parse dates and times according to specific languages and regions (locales) as well as custom format options. It addresses the issue of differences in date and time display formats across various linguistic and cultural environments, such as year-month-day order, weekday/month names, calendar types, timezone representation, etc. Mastering it allows you to develop web applications suitable for a global user base.

Solution Process / Principle Explanation

Step 1: Basic Concepts and Creating an Instance

Intl.DateTimeFormat is a constructor. You can create a formatter instance using the new operator. Two parameters can be passed during creation:

  1. locales (optional): A string or an array of strings specifying the language and region to use. For example, 'en-US', 'zh-CN', ['de-DE', 'en-GB']. If not provided or undefined is provided, the runtime environment's default locale setting will be used.
  2. options (optional): A configuration object used to control the detailed information of the formatted output, such as whether to display each part of the date, format style, calendar type, timezone, etc.
// Create a simple formatter for American English
const usFormatter = new Intl.DateTimeFormat('en-US');
// Create a formatter for Simplified Chinese with specific options
const cnFormatter = new Intl.DateTimeFormat('zh-CN', { weekday: 'long' });

Step 2: Core Method format()

After creating the formatter instance, its main purpose is to format a Date object into a string that conforms to the locale via the format() method.

const date = new Date('2023-11-05T14:48:00Z'); // Create a specific date object

console.log(usFormatter.format(date)); // Output (in the en-US locale): "11/5/2023"
console.log(cnFormatter.format(date)); // Output (in the zh-CN locale, showing only the weekday): "星期日"

Note: Internally, the format() method first calls the toISOString() method of its argument (if it is a Date object) to ensure processing a valid date. However, more crucially, the formatting process considers the following two points:

  1. Timezone Conversion: By default, Intl.DateTimeFormat uses the runtime environment's local timezone to display the time. In the example above, the input is UTC time 14:48, and the output will be adjusted based on your computer's timezone. For instance, if you are in the UTC+8 timezone, usFormatter.format(date) might display a result like "11/5/2023, 10:48 PM" (if the default includes the time part).
  2. Locale Formatting Rules: Numbers, names, order, etc., all follow the locales parameter passed.

Step 3: Detailed Explanation of Formatting Options

The options object provides fine-grained control. Main properties can be categorized as follows:

A. Date Components and Styles
You can specify whether to display and the display style for individual components like year, month, day, weekday, hour, minute, second, timezone, etc.

  • weekday: Weekday, possible values: 'narrow' (e.g., "S"), 'short' (e.g., "Sun"), 'long' (e.g., "Sunday").
  • era: Era, possible values: 'narrow', 'short', 'long'. E.g., "BC", "AD".
  • year: Year, possible values: 'numeric' (e.g., "2023"), '2-digit' (e.g., "23").
  • month: Month, possible values: 'numeric' (e.g., "11"), '2-digit' (e.g., "11"), 'short' (e.g., "Nov"), 'long' (e.g., "November"), 'narrow' (e.g., "N").
  • day: Day, possible values: 'numeric' (e.g., "5"), '2-digit' (e.g., "05").
  • hour: Hour, possible values: 'numeric' (e.g., "14"), '2-digit' (e.g., "14").
  • minute: Minute, possible values: 'numeric', '2-digit'.
  • second: Second, possible values: 'numeric', '2-digit'.
  • timeZoneName: Timezone name, possible values: 'short' (e.g., "GMT+8"), 'long' (e.g., "China Standard Time"), 'shortOffset', 'longOffset', etc.
const date = new Date('2023-11-05T14:48:00Z');
const formatter = new Intl.DateTimeFormat('en-US', {
  year: 'numeric',
  month: 'long',
  day: '2-digit',
  weekday: 'short',
  hour: '2-digit',
  minute: '2-digit',
  timeZoneName: 'short'
});
console.log(formatter.format(date)); // Example: "Sun, November 05, 2023, 10:48 PM GMT+8"

B. Overall Formatting Style
The dateStyle and timeStyle properties provide preset common formats, which are more convenient than setting each component individually. Possible values are 'full', 'long', 'medium', 'short'.

  • Note: dateStyle and timeStyle cannot be used simultaneously with the individually set component properties (like hour, month, etc.) mentioned above.
const date = new Date();
console.log(new Intl.DateTimeFormat('zh-CN', { dateStyle: 'full', timeStyle: 'long' }).format(date));
// Example output: "2023年11月5日星期日 中国标准时间 22:48:00"
console.log(new Intl.DateTimeFormat('en-GB', { dateStyle: 'short', timeStyle: 'short' }).format(date));
// Example output: "05/11/2023, 22:48"

C. Timezone, Calendar, Numbering System

  • timeZone: Explicitly specify the timezone, e.g., 'Asia/Shanghai', 'America/New_York', 'UTC'. If not specified, the runtime environment's timezone is used.
  • calendar: Specify the calendar type, e.g., 'gregory' (Gregorian calendar), 'chinese' (Chinese lunar calendar), etc. Requires runtime environment support.
  • numberingSystem: Specify the numbering system for digits, e.g., 'arab' (Arabic numerals), 'hanidec' (Chinese decimal numerals), etc. This affects the display of numbers in dates.
const date = new Date();
const formatter = new Intl.DateTimeFormat('zh-CN-u-ca-chinese', { // Use Chinese locale and lunar calendar
  timeZone: 'Asia/Shanghai',
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  calendar: 'chinese'
});
console.log(formatter.format(date)); // Outputs the lunar date

Step 4: Getting Detailed Information of Formatted Results with formatToParts()

format() returns a concatenated string. If you need detailed information about each part of the formatted result (such as text fragments for "year", "month", "day", etc.) for further processing or custom rendering, you can use the formatToParts() method. It returns an array of objects, each containing type (e.g., 'year', 'month', 'literal') and value (the string value of that part).

const date = new Date('2023-11-05');
const formatter = new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
const parts = formatter.formatToParts(date);
console.log(parts);
// Example output:
// [
//   { type: 'month', value: 'November' },
//   { type: 'literal', value: ' ' },
//   { type: 'day', value: '5' },
//   { type: 'literal', value: ', ' },
//   { type: 'year', value: '2023' }
// ]

Step 5: Querying Locale Support

You can query whether the current runtime environment supports a given locale via the static method Intl.DateTimeFormat.supportedLocalesOf(). It returns a filtered array of supported locales.

const locales = ['zh-CN', 'en-US', 'de-DE', 'xx-YY']; // Assume 'xx-YY' is not supported
const supported = Intl.DateTimeFormat.supportedLocalesOf(locales);
console.log(supported); // Output: ["zh-CN", "en-US", "de-DE"]

Summary

The core steps of using Intl.DateTimeFormat are:

  1. Create an Instance: Construct a formatter via new Intl.DateTimeFormat(locales, options) to define the target locale and formatting rules.
  2. Format: Call the instance's format(date) method, passing a Date object to obtain a localized date-time string. Under the hood, timezone conversion, name localization, and format arrangement are performed based on options and locales.
  3. Advanced Control: Use formatToParts() to get structured parts, or supportedLocalesOf() to check compatibility.

It standardizes and simplifies the internationalized display of dates and times, eliminating the need for manual string concatenation or handling complex locale-specific rules.