Объект Date в JavaScript — базовый инструмент для работы с временем, но в нём скрыто несколько неочевидных особенностей. Ниже — частые ошибки и способы их избежать, с конкретными примерами кода.
Ошибка 1: вызов Date() без new
В чём проблема. Если написать const d = Date(), получится не объект даты, а строка с текущим временем. Такой результат нельзя использовать для вычислений или извлечения компонентов.
const d1 = Date(); console.log(typeof d1); // "string" console.log(d1 instanceof Date); // false
Правильное решение. Всегда создавайте экземпляр через new Date():
const d2 = new Date(); console.log(typeof d2); // "object" console.log(d2 instanceof Date); // true
Если нужна только временная метка (timestamp в миллисекундах), используйте Date.now() — это быстрее и понятнее, чем new Date().getTime().
const ts = Date.now(); // число (ms с 1970-01-01 UTC)
Ошибка 2: месяцы в числовом конструкторе начинаются с 0
В чём проблема. При создании даты через числа new Date(year, month, day) месяц передаётся как индекс: 0 — январь, 11 — декабрь. Это частый источник смещения на один месяц.
// Ошибочно: хотели 15 февраля 2024, но получили март const wrong = new Date(2024, 2, 15); console.log(wrong.toLocaleDateString('ru-RU')); // 15.03.2024
Правильное решение. Учитывайте смещение: monthIndex = monthNumber - 1.
const monthNumber = 2; // февраль const correct = new Date(2024, monthNumber - 1, 15); console.log(correct.toLocaleDateString('ru-RU')); // 15.02.2024
Ошибка 3: парсинг произвольных строковых форматов
В чём проблема. Конструктор new Date(string) чувствителен к формату строки. Поведение различается между браузерами, а нестандартные форматы могут давать Invalid Date или неверные результаты.
// Нестабильно: может не работать или давать разные результаты const d = new Date('15/02/2024'); console.log(d.toString()); // зависит от реализации
Правильное решение. Используйте ISO 8601: YYYY-MM-DD или YYYY-MM-DDTHH:mm:ssZ.
const iso = new Date('2024-02-15T10:30:00Z'); console.log(iso.toISOString()); // "2024-02-15T10:30:00.000Z"
Для произвольных форматов лучше явно разбирать строку вручную или использовать библиотеку (например, date-fns, Luxon).
Ошибка 4: ожидание исключения при невалидной дате
В чём проблема. new Date('не дата') не выбрасывает ошибку. Вместо этого создаётся объект со статусом Invalid Date. При этом typeof всё равно возвращает "object".
const bad = new Date('not-a-date'); console.log(bad.toString()); // "Invalid Date" console.log(Number.isNaN(bad.getTime())); // true
Правильное решение. Проверяйте валидность через Number.isNaN(date.getTime()).
function isValidDate(date) { return date instanceof Date && !Number.isNaN(date.getTime()); }
Ошибка 5: сравнение объектов Date через ===
В чём проблема. Объекты сравниваются по ссылке, поэтому две даты с одинаковым временем не равны.
const a = new Date(2024, 0, 1); const b = new Date(2024, 0, 1); console.log(a === b); // false
Правильное решение. Сравнивайте временные метки:
console.log(+a === +b); // true console.log(a.getTime() === b.getTime()); // true
Для проверки «одна дата раньше другой»:
const start = new Date(2024, 0, 1); const end = new Date(2024, 0, 10); console.log(start < end); // true (работает благодаря приведению к числу)
Ошибка 6: путаница между локальным временем и UTC
В чём проблема. Методы getMonth(), getDate(), getHours() возвращают значения по локальному времени пользователя. Методы getUTCMonth(), getUTCHours() — по UTC. Смешение этих подходов приводит к ошибкам при работе с таймзонами.
const d = new Date('2024-01-15T12:00:00Z'); // UTC console.log(d.getHours()); // зависит от часового пояса браузера console.log(d.getUTCHours()); // 12 (всегда)
Правильное решение.
- Для хранения и передачи данных используйте UTC/ISO.
- Для отображения пользователю —
toLocaleString()с явным указаниемtimeZone.
const date = new Date('2024-01-15T12:00:00Z'); // Отображение в Москве console.log(date.toLocaleString('ru-RU', { timeZone: 'Europe/Moscow' })); // Отображение в Нью‑Йорке console.log(date.toLocaleString('en-US', { timeZone: 'America/New_York' }));
Ошибка 7: некорректное изменение компонентов даты
В чём проблема. Методы вида setMonth(), setDate() изменяют дату «на месте» и автоматически корректируют соседние компоненты. Неожиданное поведение возникает, если не учитывать эту автокоррекцию.
const d = new Date(2024, 0, 31); // 31 января d.setMonth(1); // февраль 2024 имеет 29 дней console.log(d.toLocaleDateString('ru-RU')); // 29.02.2024 (не 31.02)
Правильное решение. Если нужна предсказуемая логика (например, «плюс N дней»), лучше прибавлять миллисекунды:
function addDays(date, days) { const result = new Date(+date); // копия result.setTime(result.getTime() + days * 24 * 60 * 60 * 1000); return result; } const base = new Date(2024, 0, 31); const plus10 = addDays(base, 10); console.log(plus10.toLocaleDateString('ru-RU'));
Ошибка 8: расчёт разницы между датами без учёта миллисекунд
В чём проблема. Разность двух объектов Date — это число миллисекунд. Если забыть деление на коэффициент, результат будет неверным.
const start = new Date(2024, 0, 1); const end = new Date(2024, 0, 11); const diffMs = end - start; // миллисекунды const diffDaysWrong = diffMs / (60 * 60 * 24); // забыли умножить на 1000 const diffDaysCorrect = diffMs / (1000 * 60 * 60 * 24);
Правильное решение. Явно используйте множитель 1000 для перевода в секунды/дни.
const secondsPerDay = 1000 * 60 * 60 * 24; const days = Math.floor((end - start) / secondsPerDay);
Практические рекомендации
- Хранение и передача: используйте ISO‑строки (
toISOString()) или timestamp (Date.now()). - Отображение: применяйте
toLocaleString()с параметромtimeZone, чтобы избежать зависимости от настроек браузера. - Сложные сценарии (парсинг разных форматов, арифметические операции с учётом календаря, таймзоны): используйте проверенные библиотеки (
date-fns,dayjs,Luxon) вместо ручной реализации. - Валидация: всегда проверяйте
isValidDate(date)перед использованием даты из ненадёжного источника.
Мини‑пример: безопасный разбор строки и отображение
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <title>Работа с датой</title> </head> <body> <h2>Дата и время</h2> <div id="output"></div> <script> function isValidDate(date) { return date instanceof Date && !Number.isNaN(date.getTime()); } function parseSafe(isoString) { const date = new Date(isoString); if (!isValidDate(date)) { throw new Error('Некорректная дата'); } return date; } function formatForUser(date, locale = 'ru-RU', timeZone = 'Europe/Moscow') { return date.toLocaleString(locale, { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', timeZone, }); } const input = '2024-03-10T14:30:00Z'; const d = parseSafe(input); const formatted = formatForUser(d); // Вывод на экран в элемент с id="output" document.getElementById('output').textContent = formatted; // (Опционально) дублируем в консоль для проверки console.log(formatted); </script> </body> </html>

Этот подход минимизирует ошибки, связанные с форматами, таймзонами и валидностью данных.
