Avatar ·

Как определить, что объект Date содержит невалидную дату в JavaScript?

Всем привет! Я новичок в JavaScript и столкнулся с проблемой при работе с датами. Мне нужно парсить строки, которые могут содержать как корректные даты (например, "2024-10-15"), так и мусор (например, "abc" или "32.13.2024"). Я использую конструктор `new Date()`, но он ведёт себя странно. Вот пример: ```javascript let date1 = new Date("2024-10-15"); // работает let date2 = new Date("abc"); // тоже создаёт объект! ``` Проблема в том, что `new Date("abc")` не выбрасывает ошибку, а создаёт объект Date с внутренним значением `NaN`. Когда я пытаюсь вывести его через `console.log`, вижу `Invalid Date`. Но как мне программно проверить, что дата невалидна? Метод `typeof` показывает "object", а `instanceof Date` возвращает `true` даже для мусора. Пробовал сравнивать с `NaN` — не работает, потому что `NaN !== NaN`. Использовал `isNaN(date1)` — но он возвращает `false` для валидной даты и `true` для невалидной, но это работает нестабильно. Как правильно и надёжно проверять, что объект Date содержит реальную дату, а не "Invalid Date"? Нужно решение для реального проекта, желательно без сторонних библиотек. Заранее спасибо! <<>>

Проверка валидности даты через getTime()

Ключевая особенность невалидного объекта Date — его числовое представление равно NaN. Именно это свойство можно использовать для надёжной проверки. Самый распространённый и надёжный способ — вызвать метод getTime(), который возвращает количество миллисекунд с 1 января 1970 года. Для невалидной даты он возвращает NaN.

function isValidDate(date) {
    // Проверяем, что аргумент — экземпляр Date
    if (!(date instanceof Date)) {
        return false;
    }
    // Проверяем, что getTime() не возвращает NaN
    return !isNaN(date.getTime());
}

// Примеры использования:
console.log(isValidDate(new Date("2024-10-15"))); // true
console.log(isValidDate(new Date("abc")));        // false
console.log(isValidDate(new Date("32.13.2024"))); // false
console.log(isValidDate(new Date()));             // true
console.log(isValidDate("строка"));               // false (не Date)
console.log(isValidDate(null));                   // false

Почему это работает? Метод getTime() преобразует дату в число. Для "Invalid Date" это число — NaN. Функция isNaN() надёжно определяет, является ли значение NaN, в отличие от сравнения date.getTime() === NaN (которое всегда false).

Дополнительная проверка строки перед созданием Date

Иногда нужно проверить строку ещё до создания объекта Date. Это полезно, если вы хотите избежать создания мусорных объектов. Вот более продвинутая версия:

function parseAndValidateDate(dateString) {
    const date = new Date(dateString);
    
    // Проверка: объект создан, но невалиден
    if (isNaN(date.getTime())) {
        return null; // или выбросить ошибку
    }
    
    // Дополнительная проверка для строк вроде "2024-13-01" (месяц 13)
    // Парсинг может "съесть" переполнение, поэтому сравниваем компоненты
    const parts = dateString.split('-');
    if (parts.length === 3) {
        const year = parseInt(parts[0], 10);
        const month = parseInt(parts[1], 10) - 1; // месяцы с 0
        const day = parseInt(parts[2], 10);
        
        // Если исходная дата была невалидной, компоненты не совпадут
        if (date.getFullYear() !== year || 
            date.getMonth() !== month || 
            date.getDate() !== day) {
            return null;
        }
    }
    
    return date;
}

console.log(parseAndValidateDate("2024-02-30")); // null (30 февраля)
console.log(parseAndValidateDate("2024-10-15")); // Date object

Проверка через преобразование в строку

Ещё один способ — использовать метод toString(). Невалидная дата возвращает строку "Invalid Date". Этот метод менее надёжен, так как зависит от локали, но для быстрой проверки подходит:

function isDateValid(date) {
    return date instanceof Date && date.toString() !== "Invalid Date";
}

Рекомендация: Используйте первый метод с getTime() — он самый быстрый, надёжный и кроссплатформенный. Дополнительную проверку компонентов добавляйте, только если вам нужно отсекать логически невалидные даты (например, 30 февраля), которые JavaScript иногда "исправляет" автоматически.

<<>>

Проверка через Number() и valueOf()

Альтернативный подход — использовать неявное преобразование объекта Date в число. Оператор унарный плюс (+) или функция Number() вызывают внутренний метод valueOf(), который для дат возвращает то же самое, что и getTime() — количество миллисекунд. Для невалидной даты это будет NaN.

function isValidDateAlt(date) {
    return date instanceof Date && !isNaN(+date);
}

// Или через valueOf() явно:
function isValidDateAlt2(date) {
    return date instanceof Date && !isNaN(date.valueOf());
}

// Пример:
console.log(isValidDateAlt(new Date("2024-10-15"))); // true
console.log(isValidDateAlt(new Date("abc")));        // false

Этот метод работает точно так же, как и с getTime(), но короче в записи. Однако есть нюанс: если вы случайно передадите в функцию не объект Date, а, например, число, то +число даст число (не NaN), и функция может ошибочно вернуть true. Поэтому проверка instanceof Date обязательна.

Когда использовать: Если вам не нужна дополнительная валидация компонентов даты, и вы уверены, что на вход подаются только объекты Date, этот способ самый лаконичный. Для продакшена я рекомендую первый ответ с getTime() — он более явный и понятный для других разработчиков.