API Intl.DateTimeFormat
Форматируйте даты и время для любого региона без внешних библиотек
Введение
Формат отображения дат различается по всему миру. 15 января 2024 года отображается как 1/15/2024 в Соединенных Штатах, 15/1/2024 в Великобритании и 2024/1/15 в Японии. Форматы времени также различаются. Американцы используют 12-часовые часы с обозначениями AM и PM, в то время как большинство стран мира используют 24-часовой формат.
Создание логики ручного форматирования дат для разных локалей — это сложный и подверженный ошибкам процесс. Необходимо учитывать порядок дня и месяца, разделители, форматы времени, преобразования часовых поясов и особые случаи, такие как некалендарные системы.
API Intl.DateTimeFormat решает эту проблему. Оно предоставляет встроенное форматирование дат и времени с учетом локали во всех современных браузерах. Внешние библиотеки не требуются.
Основы использования
Самый простой способ отформатировать дату — создать экземпляр Intl.DateTimeFormat и вызвать его метод format().
const date = new Date(2024, 0, 15, 14, 30);
const formatter = new Intl.DateTimeFormat("en-US");
formatter.format(date);
// "1/15/2024"
Измените локаль, чтобы увидеть разные форматы.
const ukFormatter = new Intl.DateTimeFormat("en-GB");
ukFormatter.format(date);
// "15/01/2024"
const japanFormatter = new Intl.DateTimeFormat("ja-JP");
japanFormatter.format(date);
// "2024/1/15"
Одна и та же дата, отформатированная тремя разными способами в зависимости от местных стандартов.
Понимание локалей
Локаль — это строка, которая идентифицирует язык и региональные предпочтения. Формат соответствует стандарту BCP 47: код языка, за которым может следовать код региона.
Примеры распространенных локалей:
"en" // Английский (общий)
"en-US" // Английский (США)
"en-GB" // Английский (Великобритания)
"es" // Испанский (общий)
"es-MX" // Испанский (Мексика)
"es-ES" // Испанский (Испания)
"zh-CN" // Китайский (Китай, упрощенный)
"zh-TW" // Китайский (Тайвань, традиционный)
Если вы не укажете параметр локали, браузер использует локаль пользователя по умолчанию.
const formatter = new Intl.DateTimeFormat();
formatter.format(date);
// Вывод зависит от локали браузера пользователя
Вы также можете указать массив локалей. Браузер использует первую поддерживаемую локаль.
const formatter = new Intl.DateTimeFormat(["es-MX", "es", "en"]);
// Использует испанский (Мексика), если доступен, затем общий испанский, затем английский
Обзор параметров форматирования
Intl.DateTimeFormat принимает объект с параметрами, который определяет, что будет отображаться в отформатированном выводе. Существует два подхода к форматированию.
Первый подход использует сокращённые стили. Они обеспечивают быстрое и стандартное форматирование.
const formatter = new Intl.DateTimeFormat("en-US", {
dateStyle: "full",
timeStyle: "short"
});
formatter.format(date);
// "Monday, January 15, 2024 at 2:30 PM"
Второй подход использует параметры компонентов. Они позволяют детально управлять каждой частью даты.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric"
});
formatter.format(date);
// "January 15, 2024 at 2:30 PM"
Нельзя смешивать сокращённые стили и параметры компонентов. Выберите один подход для каждого форматтера.
Сокращённые стили
Параметры dateStyle и timeStyle предоставляют четыре уровня предустановленного форматирования.
Параметр dateStyle форматирует часть даты.
const date = new Date(2024, 0, 15);
const full = new Intl.DateTimeFormat("en-US", { dateStyle: "full" });
full.format(date);
// "Monday, January 15, 2024"
const long = new Intl.DateTimeFormat("en-US", { dateStyle: "long" });
long.format(date);
// "January 15, 2024"
const medium = new Intl.DateTimeFormat("en-US", { dateStyle: "medium" });
medium.format(date);
// "Jan 15, 2024"
const short = new Intl.DateTimeFormat("en-US", { dateStyle: "short" });
short.format(date);
// "1/15/24"
Параметр timeStyle форматирует часть времени.
const date = new Date(2024, 0, 15, 14, 30, 45);
const full = new Intl.DateTimeFormat("en-US", { timeStyle: "full" });
full.format(date);
// "2:30:45 PM Eastern Standard Time"
const long = new Intl.DateTimeFormat("en-US", { timeStyle: "long" });
long.format(date);
// "2:30:45 PM EST"
const medium = new Intl.DateTimeFormat("en-US", { timeStyle: "medium" });
medium.format(date);
// "2:30:45 PM"
const short = new Intl.DateTimeFormat("en-US", { timeStyle: "short" });
short.format(date);
// "2:30 PM"
Комбинируйте оба параметра, чтобы форматировать дату и время вместе.
const formatter = new Intl.DateTimeFormat("en-US", {
dateStyle: "medium",
timeStyle: "short"
});
formatter.format(date);
// "Jan 15, 2024, 2:30 PM"
Сокращённые стили автоматически адаптируются к локальным соглашениям.
const usFormatter = new Intl.DateTimeFormat("en-US", {
dateStyle: "short",
timeStyle: "short"
});
usFormatter.format(date);
// "1/15/24, 2:30 PM"
const deFormatter = new Intl.DateTimeFormat("de-DE", {
dateStyle: "short",
timeStyle: "short"
});
deFormatter.format(date);
// "15.1.24, 14:30"
Немецкий формат использует точки в качестве разделителей, меняет местами день и месяц и отображает 24-часовой формат времени. Американский формат использует слэши, порядок месяц-день и 12-часовой формат с AM/PM. Одни и те же параметры, но разный вывод в зависимости от локали.
Параметры компонента
Параметры компонента предоставляют точный контроль над тем, что отображается и как. Каждый параметр указывает часть даты или времени.
Параметр year отображает год.
const formatter = new Intl.DateTimeFormat("en-US", { year: "numeric" });
formatter.format(date);
// "2024"
const twoDigit = new Intl.DateTimeFormat("en-US", { year: "2-digit" });
twoDigit.format(date);
// "24"
Параметр month отображает месяц в различных форматах.
const numeric = new Intl.DateTimeFormat("en-US", { month: "numeric" });
numeric.format(date);
// "1"
const twoDigit = new Intl.DateTimeFormat("en-US", { month: "2-digit" });
twoDigit.format(date);
// "01"
const long = new Intl.DateTimeFormat("en-US", { month: "long" });
long.format(date);
// "January"
const short = new Intl.DateTimeFormat("en-US", { month: "short" });
short.format(date);
// "Jan"
const narrow = new Intl.DateTimeFormat("en-US", { month: "narrow" });
narrow.format(date);
// "J"
Параметр day отображает день месяца.
const formatter = new Intl.DateTimeFormat("en-US", { day: "numeric" });
formatter.format(date);
// "15"
const twoDigit = new Intl.DateTimeFormat("en-US", { day: "2-digit" });
twoDigit.format(date);
// "15"
Параметр weekday отображает день недели.
const long = new Intl.DateTimeFormat("en-US", { weekday: "long" });
long.format(date);
// "Monday"
const short = new Intl.DateTimeFormat("en-US", { weekday: "short" });
short.format(date);
// "Mon"
const narrow = new Intl.DateTimeFormat("en-US", { weekday: "narrow" });
narrow.format(date);
// "M"
Комбинируйте несколько параметров компонента, чтобы создавать пользовательские форматы даты.
const formatter = new Intl.DateTimeFormat("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
});
formatter.format(date);
// "Monday, January 15, 2024"
Браузер обрабатывает пробелы и пунктуацию в соответствии с локальными стандартами.
Форматирование времени
Опции компонента времени управляют отображением часов, минут и секунд.
const date = new Date(2024, 0, 15, 14, 30, 45);
const formatter = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
second: "numeric"
});
formatter.format(date);
// "2:30:45 PM"
Опция hour12 управляет отображением времени в 12-часовом или 24-часовом формате.
const hour12 = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
hour12: true
});
hour12.format(date);
// "2:30 PM"
const hour24 = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
hour12: false
});
hour24.format(date);
// "14:30"
Опция hourCycle предоставляет более точный контроль над отображением часов. Существует четыре варианта.
// h11: 0-11
const h11 = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
hourCycle: "h11"
});
h11.format(new Date(2024, 0, 15, 0, 30));
// "0:30 AM"
// h12: 1-12
const h12 = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
hourCycle: "h12"
});
h12.format(new Date(2024, 0, 15, 0, 30));
// "12:30 AM"
// h23: 0-23
const h23 = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
hourCycle: "h23"
});
h23.format(new Date(2024, 0, 15, 0, 30));
// "0:30"
// h24: 1-24
const h24 = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
hourCycle: "h24"
});
h24.format(new Date(2024, 0, 15, 0, 30));
// "24:30"
Разница имеет значение в полночь. Цикл h11 использует 0, в то время как h12 использует 12. Аналогично, h23 использует 0, а h24 использует 24.
Опция dayPeriod добавляет описательные маркеры периода для 12-часового формата времени.
const morning = new Date(2024, 0, 15, 10, 30);
const afternoon = new Date(2024, 0, 15, 14, 30);
const night = new Date(2024, 0, 15, 22, 30);
const formatter = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
dayPeriod: "long"
});
formatter.format(morning);
// "10:30 in the morning"
formatter.format(afternoon);
// "2:30 in the afternoon"
formatter.format(night);
// "10:30 at night"
Опция dayPeriod работает только с 12-часовыми форматами времени.
Опция fractionalSecondDigits отображает точность до долей секунды.
const date = new Date(2024, 0, 15, 14, 30, 45, 123);
const oneDigit = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
second: "numeric",
fractionalSecondDigits: 1
});
oneDigit.format(date);
// "2:30:45.1 PM"
const threeDigits = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
second: "numeric",
fractionalSecondDigits: 3
});
threeDigits.format(date);
// "2:30:45.123 PM"
Вы можете указать одну, две или три дробные цифры.
Обработка часовых поясов
Опция timeZone преобразует даты в определённые часовые пояса.
const date = new Date("2024-01-15T14:30:00Z"); // Время UTC
const newYork = new Intl.DateTimeFormat("en-US", {
timeZone: "America/New_York",
dateStyle: "full",
timeStyle: "long"
});
newYork.format(date);
// "Monday, January 15, 2024 at 9:30:00 AM EST"
const tokyo = new Intl.DateTimeFormat("ja-JP", {
timeZone: "Asia/Tokyo",
dateStyle: "full",
timeStyle: "long"
});
tokyo.format(date);
// "2024年1月15日月曜日 23:30:00 日本標準時"
const london = new Intl.DateTimeFormat("en-GB", {
timeZone: "Europe/London",
dateStyle: "full",
timeStyle: "long"
});
london.format(date);
// "Monday, 15 January 2024 at 14:30:00 GMT"
Один и тот же момент времени отображается по-разному в зависимости от часового пояса. Используйте идентификаторы часовых поясов IANA, такие как America/New_York, Europe/London или Asia/Tokyo.
Опция timeZoneName отображает название часового пояса.
const formatter = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
timeZone: "America/New_York",
timeZoneName: "short"
});
formatter.format(date);
// "9:30 AM EST"
const long = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
timeZone: "America/New_York",
timeZoneName: "long"
});
long.format(date);
// "9:30 AM Eastern Standard Time"
const shortOffset = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
timeZone: "America/New_York",
timeZoneName: "shortOffset"
});
shortOffset.format(date);
// "9:30 AM GMT-5"
const longOffset = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
timeZone: "America/New_York",
timeZoneName: "longOffset"
});
longOffset.format(date);
// "9:30 AM GMT-05:00"
Различные значения timeZoneName предоставляют разный уровень детализации.
Календарные и числовые системы
Опция calendar поддерживает некатолические календари.
const date = new Date(2024, 0, 15);
const gregorian = new Intl.DateTimeFormat("en-US", {
calendar: "gregory",
year: "numeric",
month: "long",
day: "numeric"
});
gregorian.format(date);
// "January 15, 2024"
const japanese = new Intl.DateTimeFormat("ja-JP", {
calendar: "japanese",
year: "numeric",
month: "long",
day: "numeric"
});
japanese.format(date);
// "令和6年1月15日"
const islamic = new Intl.DateTimeFormat("ar-SA", {
calendar: "islamic",
year: "numeric",
month: "long",
day: "numeric"
});
islamic.format(date);
// "٦ رجب ١٤٤٥"
const chinese = new Intl.DateTimeFormat("zh-CN", {
calendar: "chinese",
year: "numeric",
month: "long",
day: "numeric"
});
chinese.format(date);
// "2023甲辰年腊月初五"
Одна и та же дата преобразуется в разные календарные системы. Доступные календари включают gregory, japanese, islamic, islamic-umalqura, islamic-tbla, islamic-civil, islamic-rgsa, chinese, hebrew, indian, persian и другие.
Опция numberingSystem отображает цифры в разных системах счисления.
const date = new Date(2024, 0, 15);
const western = new Intl.DateTimeFormat("en-US", {
numberingSystem: "latn",
year: "numeric",
month: "numeric",
day: "numeric"
});
western.format(date);
// "1/15/2024"
const arabic = new Intl.DateTimeFormat("en-US", {
numberingSystem: "arab",
year: "numeric",
month: "numeric",
day: "numeric"
});
arabic.format(date);
// "١/١٥/٢٠٢٤"
const devanagari = new Intl.DateTimeFormat("en-US", {
numberingSystem: "deva",
year: "numeric",
month: "numeric",
day: "numeric"
});
devanagari.format(date);
// "१/१५/२०२४"
const bengali = new Intl.DateTimeFormat("en-US", {
numberingSystem: "beng",
year: "numeric",
month: "numeric",
day: "numeric"
});
bengali.format(date);
// "১/১৫/২০২৪"
Доступные системы счисления включают latn (западные цифры), arab (арабско-индийские цифры), arabext (расширенные арабско-индийские цифры), beng (бенгальские цифры), deva (деванагари) и многие другие.
Форматирование диапазонов дат
Метод formatRange() форматирует диапазон дат с умным пропуском избыточной информации.
const start = new Date(2024, 0, 15);
const end = new Date(2024, 0, 20);
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
formatter.formatRange(start, end);
// "15 – 20 января 2024 г."
Форматировщик пропускает повторяющуюся информацию. Обе даты находятся в январе 2024 года, поэтому месяц и год указываются только один раз.
Если диапазон охватывает разные месяцы, оба отображаются.
const start = new Date(2024, 0, 15);
const end = new Date(2024, 1, 20);
formatter.formatRange(start, end);
// "15 января – 20 февраля 2024 г."
Если диапазон охватывает разные годы, отображается вся информация.
const start = new Date(2024, 0, 15);
const end = new Date(2025, 1, 20);
formatter.formatRange(start, end);
// "15 января 2024 г. – 20 февраля 2025 г."
Метод formatRange() также работает с диапазонами времени.
const start = new Date(2024, 0, 15, 14, 30);
const end = new Date(2024, 0, 15, 16, 45);
const formatter = new Intl.DateTimeFormat("en-US", {
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric"
});
formatter.formatRange(start, end);
// "15 января, 14:30 – 16:45"
Дата отображается один раз, так как оба времени относятся к одному дню.
Доступ к форматированным частям
Метод formatToParts() возвращает массив объектов, представляющих каждую часть форматированной даты. Это позволяет реализовать пользовательскую логику форматирования.
const date = new Date(2024, 0, 15, 14, 30);
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric"
});
const parts = formatter.formatToParts(date);
Каждый объект в массиве имеет свойства type и value.
[
{ type: "month", value: "января" },
{ type: "literal", value: " " },
{ type: "day", value: "15" },
{ type: "literal", value: ", " },
{ type: "year", value: "2024" },
{ type: "literal", value: " в " },
{ type: "hour", value: "14" },
{ type: "literal", value: ":" },
{ type: "minute", value: "30" }
]
Вы можете фильтровать и манипулировать этими частями для создания пользовательских форматов.
const dateParts = parts.filter(part =>
["month", "day", "year"].includes(part.type)
);
const dateString = dateParts.map(part => part.value).join("/");
// "января/15/2024"
Метод formatRangeToParts() предоставляет ту же функциональность для диапазонов дат.
const start = new Date(2024, 0, 15);
const end = new Date(2024, 0, 20);
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const parts = formatter.formatRangeToParts(start, end);
Каждый объект части включает свойство source, указывающее, относится ли он к начальной или конечной дате.
[
{ type: "month", value: "января", source: "startRange" },
{ type: "literal", value: " ", source: "startRange" },
{ type: "day", value: "15", source: "startRange" },
{ type: "literal", value: " – ", source: "shared" },
{ type: "day", value: "20", source: "endRange" },
{ type: "literal", value: ", ", source: "shared" },
{ type: "year", value: "2024", source: "shared" }
]
Лучшие практики
Повторно используйте экземпляры форматировщика при форматировании нескольких дат с одинаковыми параметрами. Создание форматировщика включает согласование локали и разрешение параметров, что имеет небольшую стоимость производительности.
// Менее эффективно
dates.forEach(date => {
const formatted = new Intl.DateTimeFormat("en-US").format(date);
console.log(formatted);
});
// Более эффективно
const formatter = new Intl.DateTimeFormat("en-US");
dates.forEach(date => {
const formatted = formatter.format(date);
console.log(formatted);
});
Используйте локаль браузера пользователя, когда это возможно, исключая параметр локали. Это учитывает предпочтения пользователя.
const formatter = new Intl.DateTimeFormat();
// Автоматически использует локаль браузера
Предоставляйте резервные локали при нацеливании на определенные регионы. Если предпочтительная локаль недоступна, браузер использует следующий вариант.
const formatter = new Intl.DateTimeFormat(["fr-CA", "fr", "en"]);
// Предпочитает французский (Канада), затем французский, затем английский
Используйте сокращения стилей для отображения дат и времени. Они автоматически адаптируются к соглашениям локали и требуют меньше настроек.
const formatter = new Intl.DateTimeFormat("en-US", {
dateStyle: "medium",
timeStyle: "short"
});
Используйте параметры компонентов, если вам нужен точный контроль над форматом вывода.
const formatter = new Intl.DateTimeFormat("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
});
Всегда указывайте часовой пояс при отображении времени для удаленных пользователей или для запланированных событий. Без часового пояса даты форматируются в локальном часовом поясе пользователя, что может не соответствовать вашему намерению.
const formatter = new Intl.DateTimeFormat("en-US", {
timeZone: "America/New_York",
dateStyle: "full",
timeStyle: "long"
});
Используйте formatRange() для диапазонов дат вместо форматирования каждой даты отдельно и их объединения. Этот метод умно исключает избыточную информацию.
// Менее понятно
const startFormatted = formatter.format(start);
const endFormatted = formatter.format(end);
const range = `${startFormatted} to ${endFormatted}`;
// Лучше
const range = formatter.formatRange(start, end);
Проверьте совместимость браузеров для расширенных функций, таких как dayPeriod, fractionalSecondDigits и некоторые значения timeZoneName. Все современные браузеры поддерживают основную функциональность, но новые параметры могут потребовать резервных решений для старых браузеров.