Перейти к содержимому
Тема 21 из 21
Теория

Даты и время

Зачем это нужно

Даты есть почти в любом приложении: время сообщения в чате, срок доставки, «опубликовано 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.

Частые ошибки

  1. Месяц с нуля. new Date(2026, 1, 1) — это 1 февраля. При выводе — getMonth() + 1.
  2. getDay вместо getDate. getDay — день недели, getDate — число месяца.
  3. Возраст через деление на 365. Високосные годы дают ошибку на день-два. Сравнивай годы, месяцы и дни.
  4. Сравнение через ===. Сравнивай getTime().
  5. Изменили чужую дату. setDate меняет объект — делай копию.
  6. Строка в непонятном формате. new Date("02.11.2026") разные браузеры поймут по-разному. Используй ISO 2026-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")

Сколько дней

Лёгкая+10 XP

Напиши функцию daysBetween(from, to). Обе даты — строки в формате ГГГГ-ММ-ДД. Верни, сколько дней от from до to (если to раньше — число отрицательное).

daysBetween("2026-01-01", "2026-01-31")   → 30
daysBetween("2026-03-01", "2026-02-01")   → -28

Подключи коннектор, чтобы решать задачи

Код задач выполняется на твоём компьютере — так быстрее и надёжнее, чем в браузере. Для этого нужна бесплатная программа-коннектор CodeWithMe. Подключить её нужно один раз.

Ищем коннектор на этом компьютере…

  1. 1
    Скачай коннектор для своей системы (Windows, macOS или Linux).Скачать коннекторНа странице загрузки выбери файл со своей системой в названии, например windows-amd64.
  2. 2Запусти его и выбери папку, где будут лежать твои решения. Python и Node.js он поставит туда сам, когда понадобится.
  3. 3
    Введи ниже код из 6 цифр — он написан в окне коннектора («Код для сайта CodeWithMe»). Если браузер спросит про доступ к локальной сети — разреши.

Коннектор открытый (исходный код на GitHub), работает только на твоём компьютере и выполняет код лишь после ввода кода сопряжения.