Валидация дат с isValid

Функция isValid в библиотеке date-fns предназначена для проверки корректности даты. В JavaScript объект Date может находиться в двух состояниях: представлять реальный момент времени или быть «невалидным» (Invalid Date). Именно для различения этих случаев используется isValid.


Поведение и назначение

Встроенный объект Date в JavaScript не выбрасывает исключение при создании некорректной даты. Вместо этого он создаёт объект, внутреннее значение которого становится NaN.

new Date('invalid date') // Invalid Date

Такой объект:

  • остаётся экземпляром Date
  • но содержит некорректное временное значение
  • возвращает NaN при вызове getTime()

Функция isValid решает задачу определения, можно ли считать дату валидной.


Сигнатура функции

isValid(date)

Параметры

  • date — значение типа Date, timestamp, строка или другой объект, который приводится к дате внутри date-fns

Возвращаемое значение

  • boolean:

    • true — дата корректна
    • false — дата некорректна

Базовый принцип проверки

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

Эквивалент логики:

Number.isNaN(date.getTime())

Если значение времени не является числом — дата считается невалидной.


Примеры валидных и невалидных значений

Валидные даты

import { isValid } from 'date-fns'

isValid(new Date()) 
// true

isValid(new Date(2024, 0, 1))
// true

isValid(new Date('2024-01-01'))
// true

Невалидные даты

isValid(new Date('invalid'))
// false

isValid(new Date(NaN))
// false

isValid(new Date('2024-13-40'))
// false

Поведение с различными типами входных данных

Строки

Строки преобразуются через Date.parse:

isValid('2024-01-01')
// true

isValid('not a date')
// false

При этом важно учитывать, что парсинг строк зависит от реализации движка и формата.


Числа (timestamp)

isValid(0)
// true (Unix epoch)

isValid(1700000000000)
// true

Отрицательные значения также допустимы:

isValid(-1)
// true

Объекты Date

isValid(new Date())
// true

isValid(new Date('bad input'))
// false

Внутренняя модель невалидной даты

Невалидный Date:

const d = new Date('invalid')

d.toString()
// "Invalid Date"

d.getTime()
// NaN

Ключевой признак — невозможность преобразования в числовой timestamp.


Отличие от ручных проверок

Проверка через getTime

const d = new Date('invalid')

Number.isNaN(d.getTime()) // true

Проверка через instanceof

d instanceof Date // true

Эта проверка бесполезна для валидации, так как не различает корректные и некорректные даты.


Типичные ошибки при валидации

Ошибка: проверка через truthy/falsy

if (new Date('invalid')) {
  // всегда выполнится
}

Любой объект Date является truthy.


Ошибка: сравнение с Invalid Date

new Date('invalid') === 'Invalid Date'
// false

Строковое представление не отражает внутреннее состояние.


Практическая роль isValid в цепочках date-fns

Функция часто используется как защитный слой перед другими операциями.

Пример: форматирование

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

const date = new Date('invalid')

if (isValid(date)) {
  format(date, 'yyyy-MM-dd')
}

Без проверки format может выбросить ошибку или вернуть некорректный результат.


Пример: сравнение дат

import { isValid, compareAsc } from 'date-fns'

const a = new Date('2024-01-01')
const b = new Date('invalid')

if (isValid(a) && isValid(b)) {
  compareAsc(a, b)
}

Особенности работы с timezone и строками

isValid не проверяет:

  • корректность часового пояса
  • семантическую логичность даты
  • соответствие бизнес-правилам

Пример:

isValid(new Date('2024-02-30'))
// false

Но:

isValid(new Date('2024-02-29'))
// true (в високосный год)

Граничные случаи

Очень большие даты

isValid(new Date(1e20))
// false

Очень маленькие даты

isValid(new Date(-1e20))
// false

Причина — выход за допустимый диапазон timestamp.


Поведение внутри цепочек преобразований

date-fns функции часто принимают значения, которые сначала приводятся к Date.

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

const date = parseISO('2024-01-01T00:00:00Z')

isValid(date)
// true

Если парсинг неудачен:

parseISO('bad string')
// Invalid Date

isValid(parseISO('bad string'))
// false

Сравнение с альтернативными подходами

Date.parse

!Number.isNaN(Date.parse('2024-01-01'))

Проблема: Date.parse работает со строками, но не с объектами Date.


moment.js подход (исторически)

moment('invalid').isValid()

В date-fns аналогом является чистая функция без состояния.


Роль в архитектуре обработки дат

isValid используется как фильтр входных данных перед:

  • форматированием
  • арифметикой дат
  • сериализацией
  • сравнением
  • хранением в базе данных

Типовой паттерн:

const safeDate = (value) => {
  const d = new Date(value)
  return isValid(d) ? d : null
}

Поведение при null и undefined

isValid(null)
// false

isValid(undefined)
// false

Такие значения приводятся к Invalid Date.


Итоговые наблюдения о модели проверки

  • корректность определяется через внутренний timestamp
  • любая дата с NaN считается невалидной
  • тип объекта не гарантирует валидность
  • строковые представления не участвуют в проверке напрямую
  • функция работает одинаково для Date, string и number после приведения типов