Даты, часовые пояса, Intl
↑ 2.1 JavaScript: продвинутый · ← Предыдущая · → Следующая
Зачем это на собесе
Работа с датами и локалями — источник реальных багов; ждут знания хранения UTC и
Intl.
Объяснение
Date хранит момент времени как миллисекунды от 1970-01-01 UTC; отображение зависит от часового пояса окружения.
const d = new Date("2025-06-12T10:00:00Z"); // ISO 8601 с Z — UTC
d.getTime(); d.toISOString(); // "2025-06-12T10:00:00.000Z"
new Date(2025, 5, 12); // месяцы с 0! (июнь = 5)
new Date("2025-06-12"); // UTC-полночь; "2025-06-12T00:00" — локальное время (различие!)
Date.now(); d.getTimezoneOffset();Правила: хранить и передавать время в UTC (ISO 8601), показывать в часовом поясе пользователя; календарные даты без времени (день рождения) хранить как строку YYYY-MM-DD, а не момент времени.
Intl — форматирование по локали:
new Intl.DateTimeFormat("ru-RU", { dateStyle: "long", timeStyle: "short", timeZone: "Europe/Moscow" }).format(d);
new Intl.NumberFormat("ru-RU", { style: "currency", currency: "RUB" }).format(1234.5); // "1 234,50 ₽"
new Intl.RelativeTimeFormat("ru", { numeric: "auto" }).format(-1, "day"); // "вчера"
new Intl.PluralRules("ru").select(5); // "many"
new Intl.ListFormat("ru", { type: "conjunction" }).format(["a", "b", "c"]);
["ä", "a", "z"].sort(new Intl.Collator("de").compare);Библиотеки: date-fns, Luxon, Day.js (легковесные, Moment устарел). Новый стандарт Temporal (неизменяемые типы Instant, ZonedDateTime, PlainDate) — поддержка появляется.
Часовые пояса: IANA-названия (Europe/Moscow), а не смещения; переход на летнее время делает день 23/25-часовым; на бэкенде тоже UTC.
Нюансы и подводные камни
new Date("2025-06-12")и"2025-06-12T00:00"интерпретируются по-разному.- Месяцы нумеруются с 0.
- Сложение «+ 24 часа» не равно «следующий день» при смене времени.
toLocaleStringбез явной локали и пояса даёт разные результаты на разных машинах: в тестах указывайте явно.- Сравнение дат:
getTime(), не===. - Формат чисел с запятой/точкой зависит от локали — не парсите пользовательские числа
parseFloat-ом слепо.
Практика
- Отобразите серверное UTC-время в поясе пользователя и в поясе клиники.
- Реализуйте «сколько прошло» через
RelativeTimeFormat. - Напишите тесты дат с фиксированным часовым поясом и фейковыми таймерами.
Вопросы с ответами
В каком формате хранить время?
В UTC (ISO 8601), локальное время — только для отображения.
Зачем Intl?
Корректное форматирование дат, чисел, множественных чисел и сортировки по локали без ручных таблиц.