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

Работа с датами в JavaScript сопровождается множеством скрытых проблем: некорректный ввод, неоднозначные форматы, влияние часовых поясов, особенности объекта Date, который может содержать значение Invalid Date, оставаясь при этом экземпляром Date. В библиотеке Date-fns задача валидации даты решается через набор функций, центральной из которых является isValid.


Природа некорректных дат в JavaScript

Объект Date в JavaScript не всегда гарантирует корректность содержимого. Даже при создании экземпляра через new Date() результат может оказаться невалидным:

const d = new Date('invalid-date');
console.log(d); // Invalid Date

При этом:

typeof d; // "object"
d instanceof Date; // true

Таким образом, проверка через instanceof Date не является достаточной. Объект существует, но содержит недопустимое значение времени (NaN внутри временной шкалы).

Проблема усугубляется тем, что многие операции с датой не выбрасывают исключений, а продолжают вычисления с некорректным значением:

const d = new Date('invalid-date');
console.log(d.getTime()); // NaN

Основной инструмент проверки: isValid

В Date-fns используется функция isValid, предназначенная для строгой проверки корректности даты.

import { isValid } from 'date-fns';

isValid(new Date(2024, 0, 1)); // true
isValid(new Date('invalid'));   // false

Функция проверяет не только тип объекта, но и внутреннее значение времени.


Логика работы isValid

Проверка внутри isValid основана на двух ключевых шагах:

  1. Проверка, является ли значение объектом Date
  2. Проверка, что getTime() возвращает не NaN

Упрощённая логика:

function isValid(date) {
  return date instanceof Date && !isNaN(date.getTime());
}

Частые источники невалидных дат

1. Некорректный формат строки

new Date('2024-13-40'); // Invalid Date

Даже если строка похожа на дату, выход за пределы календаря делает результат недопустимым.


2. Пустые или неопределённые значения

new Date(undefined); // текущая дата, но это частный случай
new Date(null);      // 1970-01-01T00:00:00.000Z
new Date('');        // Invalid Date

Особенно опасна пустая строка, которая приводит к невалидной дате.


3. Результат парсинга внешних данных

При работе с API часто приходят строки неизвестного формата:

const apiDate = "2024/99/99";
const date = new Date(apiDate);

isValid(date); // false

Проверка даты после парсинга ISO

Date-fns предоставляет parseISO, которая используется для строгого разбора ISO-строк:

import { parseISO, isValid } from 'date-fns';

const date = parseISO('2024-05-20T10:30:00Z');

isValid(date); // true

Если строка не соответствует ISO-формату:

const date = parseISO('not-a-date');

isValid(date); // false

Отличие isValid от проверки isDate

Функция isDate определяет только тип значения:

import { isDate } from 'date-fns';

isDate(new Date()); // true
isDate('2024-01-01'); // false

Однако она не проверяет корректность содержимого:

const d = new Date('invalid-date');

isDate(d);   // true
isValid(d);  // false

Таким образом:

  • isDate — проверка типа
  • isValid — проверка корректности значения

Нормализация даты перед проверкой

В Date-fns многие функции принимают либо Date, либо timestamp, либо строку. Однако для валидации важно привести значение к объекту Date.

import { toDate, isValid } from 'date-fns';

const value = '2024-05-01';
const date = toDate(value);

isValid(date); // true

Функция toDate преобразует входное значение в Date, но не гарантирует корректность исходных данных.


Проверка числовых timestamp

Timestamp также может быть некорректным:

const date = new Date(NaN);

isValid(date); // false

Корректный timestamp:

const date = new Date(1716163200000);

isValid(date); // true

Защита от цепочки ошибок

В реальных приложениях проверка даты часто включается в цепочку обработки данных:

import { parseISO, isValid, format } from 'date-fns';

function safeFormat(dateString) {
  const date = parseISO(dateString);

  if (!isValid(date)) {
    return null;
  }

  return format(date, 'yyyy-MM-dd');
}

Без проверки isValid форматирование может привести к некорректным результатам или распространению Invalid Date.


Особенности поведения Invalid Date

Invalid Date ведёт себя неожиданно в операциях сравнения:

const d = new Date('invalid');

d > new Date(); // false
d < new Date(); // false

Любая арифметика с таким значением приводит к NaN:

d.getTime() + 1000; // NaN

Поэтому использование isValid — единственный надёжный способ отсечь такие значения до вычислений.


Проверка массива дат

При обработке списков дат важно фильтровать невалидные элементы:

import { isValid } from 'date-fns';

const dates = [
  new Date('2024-01-01'),
  new Date('invalid'),
  new Date('2024-05-01')
];

const validDates = dates.filter(isValid);

Результат содержит только корректные даты.


Валидация пользовательского ввода

Пользовательские данные почти всегда требуют строгой проверки:

import { parse, isValid } from 'date-fns';

function validateInput(input) {
  const date = parse(input, 'dd.MM.yyyy', new Date());

  return isValid(date);
}

Здесь parse интерпретирует строку по заданному шаблону, а isValid гарантирует, что результат действительно представляет календарную дату.


Ошибки при отсутствии проверки

Отсутствие валидации приводит к каскадным ошибкам:

  • некорректная сортировка дат
  • ошибки в вычислении диапазонов
  • неверные результаты фильтрации
  • сбои при форматировании

Пример некорректной сортировки:

dates.sort((a, b) => a - b);

Если один из элементов — Invalid Date, результат становится непредсказуемым.


Комбинированный подход к проверке

Практическая стратегия часто включает несколько шагов:

import { parseISO, isValid } from 'date-fns';

function normalizeDate(value) {
  const date = typeof value === 'string'
    ? parseISO(value)
    : new Date(value);

  if (!isValid(date)) {
    return null;
  }

  return date;
}

Такой подход позволяет централизовать обработку всех типов входных данных.


Поведение при сравнении с isNaN

Иногда используется проверка:

isNaN(date.getTime())

Однако Date-fns делает это более безопасно и инкапсулированно. Прямое использование isValid снижает риск ошибок и делает код предсказуемым при работе с различными типами входных значений.


Итоговая роль проверки корректности

Проверка корректности даты в Date-fns является фундаментальным этапом обработки временных данных. Она отделяет формально существующий объект Date от действительно допустимого календарного значения, предотвращая распространение ошибок на уровне вычислений, форматирования и бизнес-логики.