Intl.DateTimeFormat полифилл

Intl.DateTimeFormat — часть спецификации ECMAScript Internationalization API (Intl), предназначенная для локализованного форматирования дат и времени. Современные браузеры и среды выполнения JavaScript поддерживают этот API нативно, однако в ряде случаев требуется полифилл:

  • поддержка старых браузеров;
  • работа в средах без полноценной ICU-базы;
  • поддержка дополнительных локалей;
  • одинаковое поведение между Node.js и браузером;
  • устранение несовместимостей между реализациями движков.

Полифилл из экосистемы FormatJS предоставляет совместимую реализацию Intl.DateTimeFormat, соответствующую современным спецификациям ECMA-402.


Пакеты полифилла

Основной пакет:

npm install @formatjs/intl-datetimeformat

Дополнительные пакеты:

npm install @formatjs/intl-locale
npm install @formatjs/intl-getcanonicallocales

Для загрузки данных локализации:

npm install @formatjs/intl-datetimeformat/locale-data/en
npm install @formatjs/intl-datetimeformat/locale-data/ru

Для поддержки таймзон:

npm install @formatjs/intl-datetimeformat/add-all-tz

Структура полифилла

Полифилл состоит из нескольких уровней:

Компонент Назначение
polyfill Добавляет API при отсутствии
polyfill-force Принудительно заменяет нативную реализацию
locale-data Данные локализации
add-all-tz База таймзон
should-polyfill Проверка необходимости полифилла

Базовое подключение

Простое подключение

import '@formatjs/intl-datetimeformat/polyfill';
import '@formatjs/intl-datetimeformat/locale-data/ru';

const formatter = new Intl.DateTimeFormat('ru');

console.log(formatter.format(new Date()));

Проверка необходимости полифилла

FormatJS предоставляет утилиту shouldPolyfill.

import {shouldPolyfill} from '@formatjs/intl-datetimeformat/should-polyfill';

if (shouldPolyfill()) {
  await import('@formatjs/intl-datetimeformat/polyfill');
  await import('@formatjs/intl-datetimeformat/locale-data/ru');
}

Подобный подход уменьшает размер итогового бандла.


Принудительное переопределение

Некоторые среды содержат частичную или некорректную реализацию Intl.DateTimeFormat. В таких случаях используется polyfill-force.

import '@formatjs/intl-datetimeformat/polyfill-force';

Теперь даже при наличии встроенного API будет использоваться реализация FormatJS.


Загрузка локалей

Полифилл не включает все локали автоматически. Каждая локаль импортируется отдельно.

Английская локаль

import '@formatjs/intl-datetimeformat/locale-data/en';

Русская локаль

import '@formatjs/intl-datetimeformat/locale-data/ru';

Несколько локалей

import '@formatjs/intl-datetimeformat/locale-data/en';
import '@formatjs/intl-datetimeformat/locale-data/ru';
import '@formatjs/intl-datetimeformat/locale-data/de';

Форматирование даты

Полная дата

const formatter = new Intl.DateTimeFormat('ru', {
  dateStyle: 'full'
});

console.log(formatter.format(new Date()));

Результат:

понедельник, 15 января 2026 г.

Форматирование времени

const formatter = new Intl.DateTimeFormat('ru', {
  timeStyle: 'medium'
});

console.log(formatter.format(new Date()));

Форматирование даты и времени

const formatter = new Intl.DateTimeFormat('ru', {
  dateStyle: 'long',
  timeStyle: 'short'
});

console.log(formatter.format(new Date()));

Использование отдельных опций

День, месяц и год

const formatter = new Intl.DateTimeFormat('ru', {
  day: '2-digit',
  month: 'long',
  year: 'numeric'
});

console.log(formatter.format(new Date()));

Форматирование времени с секундами

const formatter = new Intl.DateTimeFormat('ru', {
  hour: '2-digit',
  minute: '2-digit',
  second: '2-digit'
});

console.log(formatter.format(new Date()));

Форматирование по таймзоне

Использование UTC

const formatter = new Intl.DateTimeFormat('ru', {
  timeZone: 'UTC',
  timeStyle: 'long'
});

console.log(formatter.format(new Date()));

Подключение базы таймзон

По умолчанию полифилл не содержит полной информации о таймзонах.

Загрузка всех таймзон

import '@formatjs/intl-datetimeformat/add-all-tz';

Минимальная база таймзон

Вместо полной базы можно использовать сокращённый вариант.

import '@formatjs/intl-datetimeformat/add-golden-tz';

Такой вариант уменьшает размер бандла.


Форматирование для разных регионов

США

const us = new Intl.DateTimeFormat('en-US');

console.log(us.format(new Date()));

Германия

const de = new Intl.DateTimeFormat('de-DE');

console.log(de.format(new Date()));

Япония

const jp = new Intl.DateTimeFormat('ja-JP');

console.log(jp.format(new Date()));

Использование formatToParts

Метод formatToParts возвращает структуру форматированной даты.

const formatter = new Intl.DateTimeFormat('ru', {
  dateStyle: 'long'
});

console.log(formatter.formatToParts(new Date()));

Пример результата:

[
  { type: 'day', value: '15' },
  { type: 'literal', value: ' ' },
  { type: 'month', value: 'января' }
]

Построение собственных шаблонов

formatToParts позволяет создавать кастомное форматирование.

const formatter = new Intl.DateTimeFormat('ru', {
  hour: '2-digit',
  minute: '2-digit'
});

const parts = formatter.formatToParts(new Date());

const values = Object.fromEntries(
  parts.map(part => [part.type, part.value])
);

console.log(`${values.hour}:${values.minute}`);

Форматирование диапазонов дат

Современные реализации поддерживают formatRange.

const formatter = new Intl.DateTimeFormat('ru', {
  dateStyle: 'medium'
});

const start = new Date(2026, 0, 10);
const end = new Date(2026, 0, 15);

console.log(formatter.formatRange(start, end));

Форматирование диапазонов с детализацией

const formatter = new Intl.DateTimeFormat('ru', {
  dateStyle: 'full'
});

console.log(
  formatter.formatRangeToParts(start, end)
);

Работа с календарями

Исламский календарь

const formatter = new Intl.DateTimeFormat('ar', {
  calendar: 'islamic'
});

console.log(formatter.format(new Date()));

Использование японского календаря

const formatter = new Intl.DateTimeFormat('ja-JP-u-ca-japanese');

console.log(formatter.format(new Date()));

Использование систем нумерации

Арабские цифры

const formatter = new Intl.DateTimeFormat('ar', {
  numberingSystem: 'arab'
});

console.log(formatter.format(new Date()));

Настройка часового цикла

24-часовой формат

const formatter = new Intl.DateTimeFormat('ru', {
  hour: 'numeric',
  hourCycle: 'h23'
});

console.log(formatter.format(new Date()));

12-часовой формат

const formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  hourCycle: 'h12'
});

console.log(formatter.format(new Date()));

Использование resolvedOptions

Метод показывает итоговые настройки форматтера.

const formatter = new Intl.DateTimeFormat('ru');

console.log(formatter.resolvedOptions());

Пример результата:

{
  locale: 'ru',
  calendar: 'gregory',
  numberingSystem: 'latn',
  timeZone: 'UTC'
}

Поддержка Node.js

Подключение в Node.js

import '@formatjs/intl-datetimeformat/polyfill';
import '@formatjs/intl-datetimeformat/add-all-tz';
import '@formatjs/intl-datetimeformat/locale-data/ru';

Проблемы ICU в Node.js

Некоторые сборки Node.js содержат сокращённую ICU-базу (small-icu), из-за чего:

  • отсутствуют локали;
  • некорректно работают таймзоны;
  • ограничено форматирование.

Полифилл FormatJS устраняет эти ограничения.


Динамическая загрузка локалей

Ленивая загрузка

async function loadLocale(locale) {
  await import(
    `@formatjs/intl-datetimeformat/locale-data/${locale}`
  );
}

Оптимизация размера бандла

Неправильный подход

import '@formatjs/intl-datetimeformat/add-all-tz';

Полная база таймзон существенно увеличивает размер приложения.


Оптимизированный подход

import '@formatjs/intl-datetimeformat/add-golden-tz';

Использование с React

Создание форматтера

const formatter = new Intl.DateTimeFormat('ru', {
  dateStyle: 'long'
});

Использование в компоненте

function DateLabel({date}) {
  return (
    <span>
      {formatter.format(date)}
    </span>
  );
}

Использование с React Intl

Библиотека react-intl использует Intl.DateTimeFormat внутри своих компонентов.

<FormattedDate
  value={new Date()}
  year="numeric"
  month="long"
  day="2-digit"
/>

При отсутствии нативной поддержки автоматически применяется полифилл.


Совместимость браузеров

Полифилл особенно актуален для:

Браузер Особенности
Internet Explorer отсутствует современный Intl
Safari старых версий частичная поддержка
Android WebView ограниченная ICU
Старые Chromium отсутствуют новые API

Поддерживаемые возможности

Полифилл поддерживает:

  • format
  • formatToParts
  • formatRange
  • formatRangeToParts
  • локали Unicode
  • таймзоны
  • календари
  • numbering systems

Ограничения полифилла

Некоторые особенности зависят от объёма подключённых данных:

  • количество локалей;
  • наличие базы таймзон;
  • полнота ICU-данных;
  • поддержка нестандартных календарей.

Архитектура работы

Внутри полифилл:

  1. Анализирует локаль;
  2. Загружает CLDR-данные;
  3. Выбирает шаблон форматирования;
  4. Выполняет разбор даты;
  5. Генерирует локализованную строку.

Использование CLDR

FormatJS основан на Unicode CLDR.

CLDR содержит:

  • названия месяцев;
  • правила локалей;
  • шаблоны дат;
  • данные таймзон;
  • форматы календарей.

Разница между нативным API и полифиллом

Возможность Нативный API FormatJS
Поддержка старых браузеров Нет Да
Единое поведение Частично Да
Настраиваемые данные Нет Да
Контроль локалей Ограничен Полный
Поддержка таймзон Зависит от среды Да

Полная инициализация приложения

import '@formatjs/intl-getcanonicallocales/polyfill';
import '@formatjs/intl-locale/polyfill';

import '@formatjs/intl-datetimeformat/polyfill';
import '@formatjs/intl-datetimeformat/add-golden-tz';

import '@formatjs/intl-datetimeformat/locale-data/en';
import '@formatjs/intl-datetimeformat/locale-data/ru';

Проверка поддержки API

console.log(typeof Intl.DateTimeFormat);

Проверка локалей

console.log(
  Intl.DateTimeFormat.supportedLocalesOf([
    'ru',
    'fr',
    'ja'
  ])
);

Использование Unicode extension

Тайская система нумерации

const formatter = new Intl.DateTimeFormat(
  'th-TH-u-nu-thai'
);

console.log(formatter.format(new Date()));

Использование нескольких настроек

const formatter = new Intl.DateTimeFormat('fr-FR', {
  weekday: 'long',
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  hour: '2-digit',
  minute: '2-digit',
  timeZone: 'Europe/Paris'
});

Отладка полифилла

Проверка используемой реализации

console.log(Intl.DateTimeFormat.toString());

Проверка таймзоны

console.log(
  Intl.DateTimeFormat().resolvedOptions().timeZone
);

Распространённые ошибки

Отсутствует locale-data

Ошибка:

Missing locale data

Причина:

import '@formatjs/intl-datetimeformat/polyfill';

без:

import '@formatjs/intl-datetimeformat/locale-data/ru';

Ошибка таймзоны

Ошибка:

Invalid time zone specified

Причина — отсутствие базы таймзон.

Решение:

import '@formatjs/intl-datetimeformat/add-all-tz';

Использование в SSR

При серверном рендеринге важно:

  • синхронизировать локали;
  • использовать одинаковые таймзоны;
  • загружать одинаковые locale-data на сервере и клиенте.

Пример SSR-конфигурации

global.Intl = require('@formatjs/intl-datetimeformat');

Практический пример

import '@formatjs/intl-datetimeformat/polyfill';
import '@formatjs/intl-datetimeformat/add-golden-tz';

import '@formatjs/intl-datetimeformat/locale-data/ru';

const formatter = new Intl.DateTimeFormat('ru', {
  dateStyle: 'full',
  timeStyle: 'long',
  timeZone: 'Europe/Moscow'
});

console.log(
  formatter.format(new Date())
);