Даты, часовые пояса, Intl

↑ 2.1 JavaScript: продвинутый · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Работа с датами и локалями — источник реальных багов; ждут знания хранения 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-ом слепо.

Практика

  1. Отобразите серверное UTC-время в поясе пользователя и в поясе клиники.
  2. Реализуйте «сколько прошло» через RelativeTimeFormat.
  3. Напишите тесты дат с фиксированным часовым поясом и фейковыми таймерами.

Вопросы с ответами

Связанные темы