Даты и время
Зачем это нужно
Даты есть почти в любом приложении: время сообщения в чате, срок доставки, «опубликовано 3 дня
назад», календарь, таймер до конца акции, возраст пользователя. В JavaScript для этого есть
встроенный объект Date. У него есть несколько ловушек, которые ломают программы у новичков — и
у опытных разработчиков тоже. Разберём их.
Создать дату
const now = new Date(); // текущий момент
const newYear = new Date(2026, 0, 1); // 1 января 2026, 00:00 по местному времени
const iso = new Date("2026-11-02"); // из строки в формате ISO
const fromMs = new Date(0); // из метки времени
console.log(newYear.getFullYear(), newYear.getMonth(), newYear.getDate());
Вывод:
2026 0 1
Главная ловушка: месяцы считаются с нуля. Январь — 0, февраль — 1, декабрь — 11. А дни
месяца — с единицы, как обычно. Поэтому при выводе месяца пишут getMonth() + 1.
Метка времени
Внутри Date хранит одно число — сколько миллисекунд прошло с 1 января 1970 года по Гринвичу
(UTC). Это число называют меткой времени (timestamp):
console.log(new Date(0).toISOString());
console.log(new Date("2026-01-01T00:00:00Z").getTime());
Вывод:
1970-01-01T00:00:00.000Z
1767225600000
Текущая метка — Date.now(). Её используют, чтобы засечь время:
const start = Date.now();
for (let i = 0; i < 1e6; i++) {}
console.log("Цикл занял меньше секунды: " + (Date.now() - start < 1000));
Вывод:
Цикл занял меньше секунды: true
Части даты
| Получить | Что вернёт |
|---|---|
getFullYear() |
год, например 2026 |
getMonth() |
месяц 0–11 |
getDate() |
день месяца 1–31 |
getDay() |
день недели 0–6, где 0 — воскресенье |
getHours(), getMinutes(), getSeconds() |
время |
getTime() |
метка времени |
const d = new Date(2026, 10, 2, 14, 5); // 2 ноября 2026, 14:05
const days = ["вс", "пн", "вт", "ср", "чт", "пт", "сб"];
console.log(days[d.getDay()]);
console.log(`${d.getHours()}:${String(d.getMinutes()).padStart(2, "0")}`);
Вывод:
пн
14:05
Для каждого get… есть set…: setFullYear, setMonth, setDate, setHours…
Дата сама исправляется
Если указать «несуществующий» день, Date перенесёт лишнее на следующий месяц. Это не ошибка, а
удобный инструмент:
console.log(new Date(2026, 1, 30).getDate(), new Date(2026, 1, 30).getMonth()); // 30 февраля?
const d = new Date(2026, 11, 30);
d.setDate(d.getDate() + 5); // плюс 5 дней
console.log(d.getFullYear(), d.getMonth(), d.getDate());
const lastDay = new Date(2024, 2, 0); // «нулевое» марта = последний день февраля
console.log(lastDay.getDate());
Вывод:
2 2
2027 0 4
29
30 февраля стало 2 марта, 30 декабря + 5 дней — 4 января следующего года, а день 0 даёт
последний день предыдущего месяца (в 2024 году в феврале 29 дней).
Разница между датами
Если вычесть одну дату из другой, получится разница в миллисекундах. Чтобы перевести в дни,
делят на число миллисекунд в сутках: 1000 * 60 * 60 * 24 = 86400000:
const start = new Date("2026-09-01");
const end = new Date("2026-12-31");
const days = Math.round((end - start) / 86400000);
console.log("Дней до конца года: " + days);
Вывод:
Дней до конца года: 121
Math.round нужен из-за перехода на летнее время в некоторых странах: тогда в сутках бывает 23 или
25 часов.
ISO и часовые пояса
Самый надёжный формат даты в строке — ISO 8601: 2026-11-02T14:05:00Z. Буква Z значит
«время по UTC». Его используют сервера и JSON:
const d = new Date(Date.UTC(2026, 10, 2, 9, 30));
console.log(d.toISOString());
console.log(JSON.stringify({ created: d }));
Вывод:
2026-11-02T09:30:00.000Z
{"created":"2026-11-02T09:30:00.000Z"}
Один и тот же момент времени в разных странах выглядит по-разному: 09:30 по UTC — это 14:30 в Душанбе (UTC+5) и 12:30 в Москве (UTC+3). Поэтому:
getHours(),getDate()и другие возвращают время по часовому поясу компьютера;getUTCHours(),getUTCDate()… — по UTC;new Date("2026-11-02")(только дата) разбирается как полночь по UTC, аnew Date(2026, 10, 2)— как полночь по местному времени.
Правило: храни и передавай даты в UTC (ISO-строка или метка времени), а в местное время переводи только при показе пользователю.
Красивый вывод для людей
toLocaleDateString и toLocaleTimeString форматируют дату по правилам языка:
const d = new Date(Date.UTC(2026, 10, 2, 9, 30));
console.log(d.toLocaleDateString("ru-RU", { timeZone: "UTC" }));
console.log(d.toLocaleDateString("en-US", { timeZone: "UTC" }));
console.log(d.toLocaleDateString("ru-RU", { day: "numeric", month: "long", year: "numeric", timeZone: "UTC" }));
Вывод:
02.11.2026
11/2/2026
2 ноября 2026 г.
Без timeZone используется часовой пояс пользователя — на сайтах обычно именно это и нужно.
Как это работает внутри
Date — это обёртка над одним числом-меткой. Все get… вычисляют год, месяц и часы из этого числа
с учётом часового пояса, а set… пересчитывают метку. Поэтому две даты сравнивают через метки:
a.getTime() === b.getTime(). Обычное a === b сравнивает объекты и даст false даже для
одинаковых дат, а вот < и > работают, потому что превращают даты в числа.
Объект Date изменяемый: setDate меняет его на месте. Если дата пришла в функцию снаружи и её
нужно сдвинуть, сначала сделай копию: const copy = new Date(date);.
Для сложной работы с датами (часовые пояса, «через 2 месяца», календари) в проектах часто
используют библиотеки date-fns или dayjs, а в новых версиях JavaScript появляется встроенный
Temporal.
Частые ошибки
- Месяц с нуля.
new Date(2026, 1, 1)— это 1 февраля. При выводе —getMonth() + 1. getDayвместоgetDate.getDay— день недели,getDate— число месяца.- Возраст через деление на 365. Високосные годы дают ошибку на день-два. Сравнивай годы, месяцы и дни.
- Сравнение через
===. СравнивайgetTime(). - Изменили чужую дату.
setDateменяет объект — делай копию. - Строка в непонятном формате.
new Date("02.11.2026")разные браузеры поймут по-разному. Используй ISO2026-11-02или числа.
Шпаргалка
| Что | Как |
|---|---|
| Сейчас | new Date(), метка — Date.now() |
| Конкретная дата | new Date(2026, 10, 2) (месяц с нуля!) |
| Из ISO | new Date("2026-11-02T14:05:00Z") |
| Части | getFullYear(), getMonth() + 1, getDate(), getDay() |
| Сдвинуть | d.setDate(d.getDate() + 7) |
| Разница в днях | Math.round((b - a) / 86400000) |
| В ISO | d.toISOString() |
| Для людей | d.toLocaleDateString("ru-RU") |
| Две цифры | String(n).padStart(2, "0") |