Если вы когда-нибудь пытались вычесть одну дату из другой или просто вывести текущий месяц, вы знаете, что JavaScript может вести себя как капризный ребёнок. Но не переживайте — за 10 лет разработки я собрал все грабли, чтобы вы по ним не ходили. В этой статье мы разберём, как работать с датами и временем без боли и лишних библиотек.

Digital-студия WNDER

Знакомьтесь, объект Date

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

Создать дату можно несколькими способами:

// Текущий момент
const now = new Date();

// По строке (лучше использовать ISO-формат)
const specificDate = new Date('2025-06-15T12:00:00');

// По компонентам (месяцы с 0 до 11!)
const birthday = new Date(2025, 5, 15); // 15 июня 2025

// По миллисекундам
const fromEpoch = new Date(0); // Thu Jan 01 1970

Обратите внимание на важный момент: месяцы в JavaScript начинаются с нуля. Январь — это 0, февраль — 1 и так далее. Это частая причина багов, когда вы показываете пользователю месяц, а он на единицу меньше ожидаемого.

Основные методы: что и как получать

У объекта Date есть куча методов для получения разных частей даты. Вот самые полезные:

Метод Что возвращает Пример значения
getFullYear() Год (4 цифры) 2025
getMonth() Месяц (0-11) 5 (июнь)
getDate() День месяца (1-31) 15
getDay() День недели (0-6, воскресенье = 0) 3 (среда)
getHours() Часы (0-23) 14
getMinutes() Минуты (0-59) 30
getSeconds() Секунды (0-59) 45

Также есть методы для установки значений, например setFullYear(), setMonth() и так далее. Они меняют дату на месте и возвращают количество миллисекунд новой даты.

Обратите внимание: методы getDay() и getDate() легко перепутать. getDay() — это день недели, а getDate() — число месяца. Я сам путался первые пару лет.

Форматирование: как вывести дату красиво

Когда вы пытаетесь показать дату пользователю, просто вызвав toString(), вы получите что-то вроде "Wed Jun 15 2025 14:30:45 GMT+0300 (Москва, стандартное время)". Это не очень дружелюбно, согласитесь.

В современном JavaScript есть отличный метод toLocaleString(), который учитывает региональные настройки:

const date = new Date(2025, 5, 15, 14, 30);

// Русская локаль
console.log(date.toLocaleString('ru-RU')); // 15.06.2025, 14:30:00

// Только дата
console.log(date.toLocaleDateString('ru-RU')); // 15.06.2025

// Только время
console.log(date.toLocaleTimeString('ru-RU')); // 14:30:00

Можно даже настроить формат под свои нужды:

const options = {
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  weekday: 'long'
};

console.log(date.toLocaleDateString('ru-RU', options));
// воскресенье, 15 июня 2025 г.

Если вам нужен полностью свой формат, придётся собирать строку вручную. Например, чтобы получить "2025-06-15", можно сделать так:

function formatDate(date) {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  return `${year}-${month}-${day}`;
}

Метод padStart() здесь добавляет ноль в начало, если число меньше 10. Это простой лайфхак, который избавляет от кучи лишних проверок.

Правило: Никогда не полагайтесь на стандартный вывод даты через toString(). Всегда используйте toLocaleString() или собирайте строку вручную. Это убережёт вас от сюрпризов с часовыми поясами и форматами.

Сравнение и вычисление разницы между датами

Так как даты хранятся как числа (миллисекунды), вы можете сравнивать их напрямую с помощью операторов <, >, <= и так далее. Но будьте осторожны: оператор == не работает корректно, потому что сравниваются ссылки на объекты, а не значения. Используйте getTime() для сравнения:

const date1 = new Date(2025, 5, 15);
const date2 = new Date(2025, 5, 15);

console.log(date1 == date2);  // false (разные объекты)
console.log(date1.getTime() == date2.getTime());  // true

Для вычисления разницы просто вычтите одну дату из другой. Результат будет в миллисекундах. Чтобы перевести в дни, разделите на количество миллисекунд в сутках:

const start = new Date(2025, 5, 1);
const end = new Date(2025, 5, 15);

const diffMs = end - start; // разница в миллисекундах
const diffDays = diffMs / (1000 * 60 * 60 * 24);
console.log(diffDays); // 14

Это работает, но есть подводный камень: если между датами есть переход на летнее время (в странах, где оно есть), то в сутках может быть 23 или 25 часов. Чтобы избежать ошибок, лучше нормализовать даты до UTC:

function daysBetween(date1, date2) {
  const msPerDay = 1000 * 60 * 60 * 24;
  // Убираем время, оставляем только дату в UTC
  const utc1 = Date.UTC(date1.getFullYear(), date1.getMonth(), date1.getDate());
  const utc2 = Date.UTC(date2.getFullYear(), date2.getMonth(), date2.getDate());
  return Math.floor((utc2 - utc1) / msPerDay);
}

Подводные камни и советы

Самый большой источник головной боли — часовые пояса. Когда вы создаёте дату из строки, JavaScript интерпретирует её в местном часовом поясе браузера или сервера. Если вы передаёте дату между клиентом и сервером, лучше использовать UTC или ISO-строку с указанием часового пояса.

Например, new Date('2025-06-15') создаст дату в UTC (потому что строка без времени интерпретируется как полночь по UTC), а new Date(2025, 5, 15) — в местном времени. Это приводит к неожиданным сдвигам на день при выводе в другом часовом поясе.

Чтобы получить текущее время в UTC, используйте методы getUTCFullYear(), getUTCMonth() и так далее. А для отправки на сервер — toISOString():

const now = new Date();
console.log(now.toISOString()); // 2025-06-15T11:30:00.000Z

Буква Z на конце означает UTC.

Ещё один момент: не пытайтесь вручную добавлять дни, умножая 24 часа на количество дней. Лучше использовать setDate():

const date = new Date(2025, 5, 15);
date.setDate(date.getDate() + 30); // добавляем 30 дней
console.log(date.toDateString()); // правильно учтёт переход через месяц

Этот метод автоматически корректирует месяц и год, если нужно.

Лайфхак: Если вы работаете с датами в проекте, который требует много вычислений, рассмотрите использование библиотеки date-fns или встроенного объекта Intl.DateTimeFormat. Но для простых задач хватит и стандартного Date — главное, знать его особенности.

Современные альтернативы: Temporal

В JavaScript на подходе новый API для работы с датами — Temporal. Он уже доступен в некоторых средах как экспериментальный. Temporal решает многие проблемы Date: неизменяемость, поддержка часовых поясов, более удобные методы.

Вот как выглядит создание даты с Temporal:

// Пока не стандарт, но уже можно попробовать
const date = Temporal.PlainDate.from('2025-06-15');
console.log(date.toString()); // 2025-06-15

Но пока Temporal не полностью поддержан во всех браузерах, лучше использовать проверенные решения.

Итоговое резюме

Работа с датами в JavaScript — это не ракетостроение, но требует внимательности. Запомните главное:

  • Месяцы считаются с нуля, поэтому всегда добавляйте 1 при выводе.
  • Для сравнения дат используйте getTime(), а не ==.
  • Для вычисления разницы переводите даты в UTC, чтобы избежать проблем с часовыми поясами.
  • Используйте setDate() для добавления дней, а не ручные вычисления.
  • Для форматирования используйте toLocaleString() с нужной локалью.

Теперь вы знаете основные подводные камни и можете смело писать код, который будет правильно работать с датами. Практикуйтесь, и вскоре даты станут для вас обычным делом.

Удачи в кодинге!

Студия WNDER