Как работать с датами в JavaScript и использовать ли библиотеки
Что проверяют
Знаете ли вы, как Date на самом деле хранит время и где на нём ломаются. Следом спрашивают про часовые пояса: как показать время события пользователю в другом поясе и что хранить на сервере.
Как отвечать
Date хранит одно число: миллисекунды от 1 января 1970 года UTC. Показывать его он умеет только в UTC или в поясе браузера. Отсюда главные особенности:
- месяцы с нуля:
new Date(2026, 0, 31)это 31 января, аsetMonth(1)на такой дате даст 3 марта, потому что 31 февраля переполняется; - мутабельность:
setDateменяет объект на месте, и дата, переданная в функцию, может измениться у вызывающего кода; - парсинг:
new Date("2026-03-10")читается как полночь UTC, аnew Date("2026-03-10T10:00")как локальное время. Строки вроде"10.03.2026"движки разбирают по-разному, надёжен только ISO 8601; - форматирование: встроенный
Intl.DateTimeFormatс опциямиtimeZoneиdateStyle,Intl.RelativeTimeFormatдля «3 дня назад». Многим интерфейсам этого хватает без библиотек; - арифметика: «плюс сутки» не равно «плюс 24 часа» в дни перевода часов.
Про библиотеки: moment.js с 2020 года в режиме поддержки и не рекомендуется для новых проектов, он тяжёлый и мутабельный. Сегодня выбирают date-fns (функции поверх Date, хорошо вырезаются при сборке, пояса через @date-fns/tz), Day.js (API как у moment, пара килобайт, пояса плагином) или Luxon (иммутабельные объекты, пояса на Intl).
Будущее за Temporal: отдельные типы для даты, времени и момента с поясом, иммутабельность, корректная арифметика. Поддержка в браузерах уже появляется, но для широкой аудитории пока нужен полифил, актуальное состояние проверяйте на caniuse.
Где спотыкаются
Говорят, что Date сломается в 2038 году. Это проблема 32-битного Unix-времени, а диапазон Date около 270 тысяч лет в обе стороны от 1970.
Хранят в UTC всё, включая будущие события. Для встречи «в 10:00 по Москве» надёжнее хранить локальное время и имя пояса: правила перевода часов могут измениться.
Сравнивают даты через ===, а это сравнение ссылок на объекты. Для равенства сравнивают getTime(), а < и > работают и так, через приведение к числу.