Menu
Русский

Date в JavaScript: создание, форматирование, сравнение

Разбираемся, как на самом деле работает объект Date в JavaScript: создание дат, форматирование, арифметика, таймзоны и подводные камни, на которых спотыкаются почти все.

Объект Date — это момент во времени

Объект Date в JavaScript — это конкретный момент во времени. Внутри он хранится как обычное число: количество миллисекунд, прошедших с 1 января 1970 года по UTC (так называемая «эпоха Unix»). Всё остальное — годы, месяцы, дни, часовые пояса, форматирование — это лишь надстройка над этим числом.

index.js
Output
Click Run to see the output here.

now.getTime() — это «сырое» число миллисекунд. Всё, что умеет Date — сравнивать, прибавлять дни, форматировать — сводится к манипуляциям над этим числом и последующей его интерпретации.

Держите эту модель в голове. Date — это не «14 марта в Париже». Это универсальный момент времени, который можно отобразить как 14 марта в Париже или как 13 марта в Лос-Анджелесе — всё зависит от часового пояса, через который вы на него смотрите.

Создание объекта Date в JavaScript

Есть четыре основных способа создать Date:

index.js
Output
Click Run to see the output here.

Два важных момента:

  • Конструктор с отдельными аргументами использует месяцы с нуля. 2 — это март, а январь — 0. Это вечный источник ошибок «на единицу»: впрочем, во всём остальном API месяцы тоже нумеруются с нуля, так что хотя бы внутренне это согласовано.
  • new Date("2026-03-14") (без времени) парсится как полночь по UTC. А new Date("2026-03-14T09:30") (без Z в конце) — уже как локальное время. Эта асимметрия — классическая ловушка.

Если нужно просто «сейчас» в виде числа, лучше использовать Date.now() — так вы избежите создания лишнего объекта:

index.js
Output
Click Run to see the output here.

Date.now() — то, что нужно, когда надо замерить прошедшее время, поставить таймаут и вообще в любых ситуациях, где календарная арифметика не требуется.

Как получить части даты в JavaScript

Получив объект Date, компоненты из него достают через геттеры. У каждого геттера есть два варианта: по локальному времени и по UTC.

index.js
Output
Click Run to see the output here.

Локальные геттеры зависят от машины, на которой выполняется код. Если вы храните или сравниваете даты между пользователями и серверами, явно берите UTC — иначе будете ловить фантомные баги. Правило простое: для всего, что уходит в базу или в логи, используйте UTC-геттеры; для всего, что показываете человеку, — локальные.

Не используйте getYear(). Это легаси-метод, который возвращает year - 1900 и существует только ради обратной совместимости. Всегда берите getFullYear().

Форматирование даты для человека

Не полагайтесь на date.toString() там, где результат важен — вывод зависит от локали и движка. Есть два форматтера, которые стоит знать.

Для стандартной машиночитаемой строки подойдёт toISOString():

index.js
Output
Click Run to see the output here.

Именно такой формат стоит использовать для логов, хранения в JSON и передачи по сети. Он всегда в UTC и не допускает разночтений.

А чтобы показать дату пользователю, возьмите Intl.DateTimeFormat или методы toLocale*, которые построены поверх него:

index.js
Output
Click Run to see the output here.

Intl.DateTimeFormat умеет работать с локалями, часовыми поясами и любыми комбинациями полей, которые вам только понадобятся. Используйте его вместо ручной сборки строк вида ${year}-${month}-${day} — именно в такой склейке вручную и плодятся баги со сдвигом месяца на единицу.

Сравнение дат в JavaScript

Два объекта Date, указывающие на один и тот же момент времени, не будут равны по === — этот оператор проверяет идентичность объектов, а не их значение. Поэтому сравнивать нужно таймстемпы:

index.js
Output
Click Run to see the output here.

Для сортировки операторы сравнения работают напрямую — они приводят даты к числам:

index.js
Output
Click Run to see the output here.

Вычитание дат даёт разницу в миллисекундах. Чтобы получить дни, делим на 1000 * 60 * 60 * 24. В первый раз лучше выписать эту константу полностью — со временем число 86_400_000 начнёшь узнавать с первого взгляда.

Арифметика дат в JavaScript

Метода addDays в JavaScript нет. Идиоматичный способ — использовать setDate, setMonth и им подобные: они спокойно принимают значения за пределами обычного диапазона и сами корректно «переносят» их:

index.js
Output
Click Run to see the output here.

Пара моментов, на которые стоит обратить внимание:

  • new Date(date) создаёт копию даты. setDate меняет объект на месте, поэтому всегда сначала копируйте — иначе вы измените значение, переданное снаружи.
  • setDate(35) в месяце с 31 днём автоматически перекинет дату на следующий месяц. То же самое с setMonth(14) — год сдвинется вперёд. Благодаря этому арифметика дат на практике оказывается проще, чем кажется.

Если задача посложнее — рабочие дни, повторяющиеся события, длительности с учётом разной длины месяцев — берите библиотеку (date-fns, Luxon или будущий API Temporal). Писать собственную календарную логику дальше «прибавить пару дней» — это болото, из которого потом не выбраться.

Часовые пояса: суровая правда

Часовые пояса — главный источник багов при работе с датой и временем в javascript. Правила, которые стоит вбить себе в голову:

  • Date хранит момент времени в UTC. Часовой пояс применяется только тогда, когда вы достаёте из объекта отдельные части или форматируете его.
  • getHours(), getDate() и им подобные методы используют локальный часовой пояс машины, на которой выполняется код. У сервера и браузера он часто отличается.
  • new Date("2026-03-14") (только дата) парсится как UTC. new Date("2026-03-14T00:00") (время без указания зоны) — как локальное время. new Date(2026, 2, 14) (по частям) — тоже локальное.
index.js
Output
Click Run to see the output here.

Если нужно вывести дату в конкретном часовом поясе, передайте timeZone в Intl.DateTimeFormat:

index.js
Output
Click Run to see the output here.

Один и тот же момент времени, но два разных представления. Сам объект Date при этом никак не меняется.

Небольшой рабочий пример

Соберём всё вместе — напишем функцию, которая показывает, сколько времени прошло с какого-то события:

index.js
Output
Click Run to see the output here.

Таймштамп на входе — человекочитаемая строка на выходе. Так устроено 90% кода, работающего с датами в реальных проектах: вычли два момента времени, разделили на нужную единицу, округлили, отформатировали.

Что стоит запомнить

  • Date — это момент времени в UTC. Часовые пояса появляются только при чтении и форматировании.
  • Date.now() — для таймстампов, new Date() — для работы с календарём.
  • toISOString() — для хранения и логов, Intl.DateTimeFormat — для показа пользователю.
  • Сравнивайте через getTime() либо операторами </>. Никакого ===.
  • Месяцы нумеруются с нуля. И помните про ловушку с парсингом строк без времени.
  • Для серьёзной арифметики дат берите библиотеку.

Дальше: URL и строки запроса

Даты часто живут в URL — фильтр по диапазону, таймстамп в query-параметре. Разбирать и собирать URL вручную так же рискованно, как форматировать даты руками, и в стандартной библиотеке для этого есть объект URL, который делает всё аккуратно. Об этом — в следующей главе.

Часто задаваемые вопросы

Как получить текущую дату в JavaScript?

Вызовите new Date() без аргументов — получите объект Date с моментом, когда сработал конструктор. Если нужен просто числовой timestamp (миллисекунды с 1970 года), берите Date.now() — это быстрее и не создаёт лишний объект.

Как сравнить две даты в JavaScript?

Сравнивайте timestamp'ы, а не сами объекты Date. Работает a.getTime() < b.getTime(), а также просто a < b — оператор < приведёт даты к числу. А вот a === b не сработает: === сравнивает ссылки на объекты, поэтому две разные переменные Date с одним и тем же моментом никогда не будут строго равны.

Как отформатировать дату в JavaScript?

Для вывода пользователю используйте Intl.DateTimeFormat или date.toLocaleDateString() — они нормально работают с локалями и таймзонами. Для машинного формата подойдёт date.toISOString(), он возвращает стандартную строку вида 2026-03-14T09:30:00.000Z. А вот date.toString() для хранения лучше не использовать — формат зависит от локали.

Почему дата в JavaScript сдвинулась на один день?

Почти всегда это проблема с таймзоной. new Date('2026-03-14') парсится как полночь по UTC, а date.getDate() возвращает день уже в локальной таймзоне — и это может оказаться вчерашний день. Используйте getUTCDate() для UTC-дня или создавайте дату через new Date(year, month, day) — такой конструктор сразу работает в локальном времени.

Учитесь программировать с Coddy

НАЧАТЬ