$ sudo teach IT
МОДУЛЬ 12 · УРОК 5

Работа с датами: объект Date

Дата рождения, срок действия промокода, сколько дней до отпуска — в каждом реальном приложении работа с датами неизбежна. JavaScript предоставляет встроенный объект Date. Разберём его от и до — включая главный сюрприз: почему январь — это 0.

⏱ ~20 минут 🎓 Для новичков 📅 Date API

🗓️ Создание объекта Date

Объект Date в JavaScript представляет конкретный момент времени. Создать его можно несколькими способами:

// Текущая дата и время
const now = new Date();
console.log(now); // Tue Jun 24 2026 15:30:00 GMT+0300

// Из строки (ISO 8601 формат — надёжнее всего)
const birthday = new Date("2000-03-15");
const withTime = new Date("2026-01-15T10:30:00");

// Из чисел: год, месяц (0-11!), день, часы, минуты, секунды
const specific = new Date(2026, 5, 24); // 24 ИЮНЯ 2026 (5 = июнь)
// Внимание: месяцы от 0 до 11!

// Из timestamp — миллисекунды с 1 января 1970 (Unix Epoch)
const fromTimestamp = new Date(0);          // 1 января 1970
const fromMs = new Date(1000000000000);     // 9 сентября 2001

⚠️ Главная ловушка: в конструкторе new Date(год, месяц, день) месяцы нумеруются от 0 до 11! Январь = 0, февраль = 1, ... декабрь = 11. При чтении (getMonth()) та же история.

🤔 Почему getMonth() возвращает 0-11? Историческая причина

Это один из самых известных «приколов» JavaScript, который удивляет всех новичков. Почему январь — это 0, а не 1?

JavaScript создавался в 1995 году, и Брендан Эйх (создатель языка) позаимствовал объект Date из языка Java, который в свою очередь скопировал его из библиотеки C. В библиотеке C месяцы представлялись как индексы в массиве названий: months[0] = "January". Вот так историческая случайность стала «стандартом», который уже не исправить — иначе сломается весь существующий код.

💡 Простое правило: при создании даты — отнимайте 1 от номера месяца. При отображении — прибавляйте 1. Или используйте библиотеку date-fns — там всё по-человечески.

// Запомнить легко: getMonth() + 1 = человеческий номер месяца
const date = new Date(2026, 5, 24); // 24 июня (5+1=6=июнь)

console.log(date.getMonth());     // 5 — машинный (0-based)
console.log(date.getMonth() + 1); // 6 — человеческий

// Создать 15 января 2026:
const jan = new Date(2026, 0, 15); // месяц 0 = январь

📖 Методы получения компонентов даты

Объект Date предоставляет методы для получения каждой части даты и времени:

const date = new Date("2026-06-24T15:30:45");

// Дата
date.getFullYear();   // 2026 — год (4 цифры)
date.getMonth();      // 5 — месяц (0-11, помним!)
date.getDate();       // 24 — день месяца (1-31)
date.getDay();        // 3 — день недели (0=вс, 1=пн, ..., 6=сб)

// Время
date.getHours();      // 15 — часы (0-23)
date.getMinutes();    // 30 — минуты (0-59)
date.getSeconds();    // 45 — секунды (0-59)
date.getMilliseconds(); // 0 — миллисекунды

// Timestamp — миллисекунды с 1970-01-01
date.getTime();       // 1782306645000 (примерно)

⚠️ День недели: getDay() возвращает 0 для воскресенья и 6 для субботы. Это американская традиция — неделя начинается с воскресенья. Для нас привычнее 1 = понедельник, поэтому часто делают: date.getDay() || 7 — превращает воскресенье в 7.

🎨 Форматирование дат для отображения

Объект Date сам по себе отображается некрасиво. Для форматирования есть несколько вариантов:

const date = new Date("2026-06-24T15:30:00");

// toLocaleDateString() — форматирование даты по локали
date.toLocaleDateString("ru-RU");
// "24.06.2026"

date.toLocaleDateString("ru-RU", {
  weekday: "long",
  year: "numeric",
  month: "long",
  day: "numeric"
});
// "среда, 24 июня 2026 г."

// toLocaleTimeString() — форматирование времени
date.toLocaleTimeString("ru-RU");
// "15:30:00"

date.toLocaleTimeString("ru-RU", {
  hour: "2-digit",
  minute: "2-digit"
});
// "15:30"

// toLocaleString() — дата и время вместе
date.toLocaleString("ru-RU");
// "24.06.2026, 15:30:00"

// ISO формат — для хранения и передачи данных (API, базы данных)
date.toISOString();
// "2026-06-24T12:30:00.000Z" (UTC время)

💡 Рекомендация: для хранения дат (в базе данных, API) используйте ISO формат (toISOString()). Для отображения пользователю — toLocaleDateString() с нужной локалью.

⏱️ Date.now() и вычисление разницы дат

Date.now() — статический метод, который возвращает текущее время как timestamp (миллисекунды с 1970-01-01). Это самый быстрый способ получить текущее время — без создания объекта Date.

// Текущий timestamp
const now = Date.now();
console.log(now); // 1782306645000 (примерно)

// Замерить время выполнения кода
const start = Date.now();

// ... какой-то код ...
for (let i = 0; i < 1000000; i++) { /* работа */ }

const elapsed = Date.now() - start;
console.log(`Выполнено за ${elapsed} мс`);

Для вычисления разницы между датами используйте тот факт, что Date можно вычитать — JavaScript автоматически конвертирует их в timestamp:

// Вычисление разницы дат
const birthday = new Date("2000-06-24");
const today = new Date();

// Разница в миллисекундах
const diffMs = today - birthday;

// Переводим в разные единицы
const diffSeconds = Math.floor(diffMs / 1000);
const diffMinutes = Math.floor(diffMs / (1000 * 60));
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
const diffYears = Math.floor(diffDays / 365);

console.log(`Возраст: ${diffYears} лет`);
console.log(`Прожито дней: ${diffDays}`);
// Практическая задача: сколько дней до Нового года?
function daysUntilNewYear() {
  const today = new Date();
  const currentYear = today.getFullYear();

  // Создаём Новый год текущего или следующего года
  let newYear = new Date(currentYear + 1, 0, 1); // 1 января

  const diffMs = newYear - today;
  const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24));

  return diffDays;
}

console.log(`До Нового года осталось ${daysUntilNewYear()} дней`);

➕ Арифметика дат: прибавляем дни и месяцы

Объект Date хранит время в миллисекундах. Чтобы прибавить дни, умножаем на нужное количество миллисекунд. Для месяцев — используем методы-сеттеры:

// Прибавить дни
function addDays(date, days) {
  const result = new Date(date);
  result.setDate(result.getDate() + days);
  return result;
}

const today = new Date("2026-06-24");
console.log(addDays(today, 7));   // 2026-07-01 — через неделю
console.log(addDays(today, 30));  // 2026-07-24 — через месяц
console.log(addDays(today, -5));  // 2026-06-19 — 5 дней назад

// Прибавить месяцы
function addMonths(date, months) {
  const result = new Date(date);
  result.setMonth(result.getMonth() + months);
  return result;
}

console.log(addMonths(today, 3));  // 2026-09-24

💡 Для серьёзных проектов используйте библиотеку date-fns или Temporal (новый стандарт, в разработке). Они правильно обрабатывают летнее время, часовые пояса и другие тонкости.

✅ Итоги урока

  • new Date() — текущая дата; new Date(строка) — из ISO строки
  • Главный подводный камень: getMonth() возвращает 0-11, не 1-12!
  • getFullYear(), getMonth(), getDate(), getDay() — компоненты даты
  • getHours(), getMinutes(), getSeconds() — компоненты времени
  • toLocaleDateString("ru-RU") — форматирование для пользователя
  • Date.now() — текущий timestamp в миллисекундах
  • Разница дат: date1 - date2 — результат в миллисекундах
  • Прибавление дней: setDate(getDate() + n)

Следующий урок — особенный. Это не новая тема, а заключение. Поздравления с завершением курса! 🎉

Тест: Объект Date

6 вопросов

Разница между датами

Реализуйте функцию daysBetween(date1, date2), которая принимает два объекта Date и возвращает количество дней между ними (по модулю, всегда положительное). Используйте вычитание дат и перевод миллисекунд в дни.

Форматирование даты

Реализуйте функцию formatDate(date), которая принимает объект Date и возвращает строку в формате 'DD.MM.YYYY'. Используйте getDate, getMonth (не забудьте +1) и getFullYear. Добавьте ведущий ноль для дня и месяца, если нужно (padStart).