Локализация даты и времени включает не только форматирование строк, но и корректную обработку часовых поясов. Разные страны и регионы используют собственные временные зоны, правила перехода на летнее время и локальные стандарты отображения времени. Библиотека Globalize позволяет строить приложения, которые учитывают эти особенности на основе данных CLDR и возможностей Intl API.
В JavaScript объект Date хранит время в UTC, а
отображает его в локальном часовом поясе среды выполнения. Это приводит
к нескольким распространённым проблемам:
Globalize решает задачу локализованного форматирования времени, опираясь на:
Globalize.dateFormatter;Intl.DateTimeFormat.Для работы с датами и часовыми поясами требуется подключение соответствующих наборов данных.
const Globalize = require("globalize");
const cldrData = require("cldr-data");
Globalize.load(
cldrData.entireSupplemental(),
cldrData.entireMainFor("en", "ru")
);
Globalize.locale("ru");
После загрузки данных становится доступным форматирование даты и времени.
Простейший пример отображения времени:
const formatter = Globalize.dateFormatter({
datetime: "medium"
});
console.log(formatter(new Date()));
Результат для русской локали:
27 мая 2026 г., 14:30:12
Для английской локали:
Globalize.locale("en");
console.log(formatter(new Date()));
Результат:
May 27, 2026, 2:30:12 PM
Формат автоматически адаптируется под культуру пользователя.
Globalize не реализует собственный движок временных зон. Вместо этого
библиотека использует возможности Intl.DateTimeFormat.
Пример форматирования времени для конкретного часового пояса:
const date = new Date();
const formatter = new Intl.DateTimeFormat("ru-RU", {
timeZone: "Europe/Moscow",
dateStyle: "full",
timeStyle: "long"
});
console.log(formatter.format(date));
Результат:
среда, 27 мая 2026 г. в 14:30:12 GMT+3
Временные зоны задаются в формате IANA Time Zone Database.
| Регион | Идентификатор |
|---|---|
| Москва | Europe/Moscow |
| Алматы | Asia/Almaty |
| Нью-Йорк | America/New_York |
| Лондон | Europe/London |
| Токио | Asia/Tokyo |
Использование неверного идентификатора приводит к ошибке:
new Intl.DateTimeFormat("ru-RU", {
timeZone: "Moscow"
});
Ошибка:
RangeError: Invalid time zone specified
На практике часто используется совместная работа двух механизмов:
Пример:
Globalize.locale("ru");
const date = new Date();
const formatter = new Intl.DateTimeFormat(
Globalize.locale().attributes.language,
{
timeZone: "Asia/Almaty",
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
hour: "2-digit",
minute: "2-digit"
}
);
console.log(formatter.format(date));
Результат:
среда, 27 мая 2026 г., 16:30
Определение временной зоны производится через
Intl.DateTimeFormat.
const timezone =
Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log(timezone);
Пример результата:
Asia/Almaty
Это особенно важно для:
Сервер обычно хранит время в UTC.
Пример UTC-даты:
const utcDate = new Date("2026-05-27T10:00:00Z");
Преобразование для Москвы:
const moscowFormatter = new Intl.DateTimeFormat("ru-RU", {
timeZone: "Europe/Moscow",
timeStyle: "short"
});
console.log(moscowFormatter.format(utcDate));
Результат:
13:00
Преобразование для Нью-Йорка:
const nyFormatter = new Intl.DateTimeFormat("en-US", {
timeZone: "America/New_York",
timeStyle: "short"
});
console.log(nyFormatter.format(utcDate));
Результат:
6:00 AM
UTC используется как универсальная временная основа.
Создание UTC-времени:
const date = new Date(Date.UTC(
2026,
4,
27,
10,
0,
0
));
Форматирование:
const formatter = new Intl.DateTimeFormat("ru-RU", {
timeZone: "UTC",
dateStyle: "full",
timeStyle: "long"
});
console.log(formatter.format(date));
Результат:
среда, 27 мая 2026 г. в 10:00:00 UTC
Многие страны используют DST (Daylight Saving Time). Intl автоматически учитывает эти изменения.
Пример:
const winter = new Date("2026-01-15T12:00:00Z");
const summer = new Date("2026-07-15T12:00:00Z");
const formatter = new Intl.DateTimeFormat("en-US", {
timeZone: "America/New_York",
timeZoneName: "short"
});
console.log(formatter.format(winter));
console.log(formatter.format(summer));
Результат:
1/15/2026, EST
7/15/2026, EDT
Смещение меняется автоматически.
Параметр timeZoneName управляет отображением зоны.
const formatter = new Intl.DateTimeFormat("ru-RU", {
timeZone: "Europe/Moscow",
timeZoneName: "short"
});
Результат:
GMT+3
const formatter = new Intl.DateTimeFormat("ru-RU", {
timeZone: "Europe/Moscow",
timeZoneName: "long"
});
Результат:
Москва, стандартное время
const formatter = new Intl.DateTimeFormat("ru-RU", {
timeZone: "Asia/Tokyo",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
});
console.log(formatter.format(new Date()));
Результат:
22:15:48
const formatter = new Intl.DateTimeFormat("ru-RU", {
timeZone: "Europe/London",
year: "numeric",
month: "long",
day: "numeric"
});
console.log(formatter.format(new Date()));
Результат:
27 мая 2026 г.
Globalize поддерживает CLDR-шаблоны форматирования.
const formatter = Globalize.dateFormatter({
skeleton: "GyMMMd"
});
console.log(formatter(new Date()));
Результат:
27 мая 2026 г.
| Шаблон | Назначение |
|---|---|
Hm |
часы и минуты |
Hms |
часы, минуты, секунды |
yMd |
дата |
yMMMd |
дата с названием месяца |
GyMMMd |
дата с эрой |
JavaScript не изменяет сам объект Date при смене зоны.
Меняется только представление.
Пример:
const date = new Date("2026-05-27T10:00:00Z");
const zones = [
"Europe/Moscow",
"Asia/Tokyo",
"America/New_York"
];
zones.forEach(zone => {
const formatter = new Intl.DateTimeFormat("en-US", {
timeZone: zone,
timeStyle: "long"
});
console.log(zone, formatter.format(date));
});
Результат:
Europe/Moscow 1:00:00 PM GMT+3
Asia/Tokyo 7:00:00 PM GMT+9
America/New_York 6:00:00 AM EDT
Неправильно:
const localDate = new Date();
database.save(localDate);
Правильно:
database.save(new Date().toISOString());
Неправильно:
const hours = utcHours + 3;
Проблемы:
Правильный подход:
new Intl.DateTimeFormat("ru-RU", {
timeZone: "Europe/Moscow"
});
Неправильно:
timeZone: "MSK"
Правильно:
timeZone: "Europe/Moscow"
Globalize и Intl поддерживаются:
| Среда | Поддержка |
|---|---|
| Chrome | Полная |
| Firefox | Полная |
| Safari | Полная |
| Edge | Полная |
| Node.js | Полная при наличии ICU |
Для корректной интернационализации Node.js должен содержать ICU-данные.
Проверка поддержки:
console.log(
Intl.DateTimeFormat.supportedLocalesOf(["ru"])
);
Если массив пустой, ICU отсутствует или подключён частично.
Хотя Globalize ориентирован на Intl, иногда применяется связка с Moment Timezone.
Установка:
npm install moment moment-timezone
Пример:
const moment = require("moment-timezone");
const date = moment.utc("2026-05-27T10:00:00Z");
console.log(
date.tz("Asia/Almaty").format("HH:mm")
);
Результат:
16:00
После вычислений строка может дополнительно локализоваться через Globalize.
Luxon считается более современным решением.
Установка:
npm install luxon
Пример:
const { DateTime } = require("luxon");
const dt = DateTime
.utc()
.setZone("Europe/Moscow");
console.log(
dt.toLocaleString(DateTime.DATETIME_FULL)
);
Luxon хорошо сочетается с концепцией Intl и CLDR.
Типичная схема:
Пример:
const utcDate = "2026-05-27T10:00:00Z";
const userZone =
Intl.DateTimeFormat()
.resolvedOptions()
.timeZone;
const formatter = new Intl.DateTimeFormat("ru-RU", {
timeZone: userZone,
dateStyle: "full",
timeStyle: "short"
});
console.log(
formatter.format(new Date(utcDate))
);
Создание форматтера — относительно дорогая операция.
Неправильно:
for (const item of items) {
const formatter = new Intl.DateTimeFormat("ru-RU");
formatter.format(item.date);
}
Правильно:
const formatter =
new Intl.DateTimeFormat("ru-RU");
for (const item of items) {
formatter.format(item.date);
}
Кэширование форматтеров особенно важно:
Globalize.locale("ru");
const meetings = [
{
title: "Daily Meeting",
date: "2026-05-27T09:00:00Z"
},
{
title: "Deploy",
date: "2026-05-27T15:00:00Z"
}
];
const timezone =
Intl.DateTimeFormat()
.resolvedOptions()
.timeZone;
const formatter = new Intl.DateTimeFormat("ru-RU", {
timeZone: timezone,
dateStyle: "short",
timeStyle: "short"
});
meetings.forEach(meeting => {
console.log(
meeting.title,
formatter.format(new Date(meeting.date))
);
});
Такой подход обеспечивает: