Даты: date schema

Работа с датами в схемах валидации является одной из наиболее чувствительных частей прикладной логики, поскольку включает в себя неоднозначность форматов, влияние временных зон, особенности парсинга строк и поведение JavaScript-объекта Date. В Yup для этих задач предусмотрен специализированный тип date, основанный на mixed, но дополненный набором правил и преобразований, ориентированных именно на работу с временными значениями.


Базовое определение date-схемы

Основой служит Yup.date(), создающий схему, которая ожидает значение, приводимое к объекту Date.

import * as Yup from 'yup';

const schema = Yup.date();

Внутренне происходит попытка преобразования входного значения в Date через new Date(value). Это означает, что допустимыми являются:

  • экземпляры Date
  • строки в ISO-формате
  • числовые timestamp
  • некоторые строковые представления даты, поддерживаемые движком JavaScript

Преобразование значений и нюансы парсинга

Поведение преобразования зависит от валидности входных данных:

Yup.date().isValidSync('2026-01-01'); // true
Yup.date().isValidSync('invalid');    // false

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

Ключевые особенности:

  • ISO 8601 считается наиболее стабильным форматом
  • локальные форматы строк могут быть некорректно интерпретированы
  • пустые строки преобразуются в Invalid Date

Обязательность значения

Для указания обязательного значения используется .required():

const schema = Yup.date().required('Дата обязательна');

Если значение отсутствует (undefined, null или пустое поле формы), валидация не проходит.


Ограничение диапазона дат

Минимальная дата

Метод .min() ограничивает нижнюю границу допустимого диапазона:

const schema = Yup.date().min(new Date(2020, 0, 1));

Можно также использовать строку:

Yup.date().min('2020-01-01');

Максимальная дата

Аналогично применяется .max():

const schema = Yup.date().max(new Date());

Это часто используется для предотвращения ввода будущих дат в полях, где это недопустимо (например, дата рождения).


Работа с временными зонами

JavaScript Date всегда хранит значение в UTC, но отображение зависит от локальной зоны.

При валидации через Yup важно учитывать:

  • строка "2026-01-01" интерпретируется как UTC полуночь
  • локальные смещения могут сдвигать дату на предыдущий день при отображении
  • сравнения .min() и .max() выполняются по timestamp (UTC)

Это приводит к частым ошибкам в бизнес-логике, если не учитывать временную зону при нормализации данных.


Запрет null и работа с nullable

По умолчанию null считается невалидным значением для даты.

Yup.date().nullable();

С nullable() схема начинает принимать null как допустимое значение, что важно для форм с необязательными полями.


Проверка корректности типа

Для перехвата некорректных значений используется .typeError():

Yup.date().typeError('Некорректный формат даты');

Это позволяет разделить ошибки:

  • отсутствие значения (required)
  • неверный тип или формат (typeError)

Значение по умолчанию

Метод .default() задаёт автоматическое заполнение:

Yup.date().default(() => new Date());

или фиксированное значение:

Yup.date().default(new Date(2000, 0, 1));

При использовании с .required() важно учитывать порядок применения: default применяется до валидации.


Кастомная трансформация входных данных

Метод .transform() позволяет управлять преобразованием до проверки:

const schema = Yup.date().transform((value, originalValue) => {
  return originalValue === '' ? null : value;
});

Это особенно важно для форм, где пустая строка передаётся как значение поля.


Кастомная логика через test

Для более сложных проверок используется .test():

const schema = Yup.date().test(
  'not-weekend',
  'Выходные даты запрещены',
  (value) => {
    if (!value) return true;
    const day = value.getDay();
    return day !== 0 && day !== 6;
  }
);

Такая схема позволяет внедрять бизнес-ограничения, которые невозможно выразить стандартными методами .min() и .max().


Сравнение дат между собой

Частый кейс — зависимость двух дат:

const schema = Yup.object({
  startDate: Yup.date().required(),
  endDate: Yup.date()
    .min(Yup.ref('startDate'), 'Конец должен быть позже начала')
});

Здесь используется Yup.ref, позволяющий ссылаться на другие поля объекта.


Использование в объектах схем

Date-схема чаще всего применяется внутри объектов:

const bookingSchema = Yup.object({
  checkIn: Yup.date().required(),
  checkOut: Yup.date()
    .min(Yup.ref('checkIn'))
    .required()
});

Такая композиция позволяет строить сложные модели данных с взаимозависимыми ограничениями.


Особенности сериализации и хранения

При работе с API важно учитывать:

  • Date при JSON.stringify превращается в ISO строку
  • при повторной валидации может происходить повторный парсинг
  • возможны потери точности при работе с невалидными строками

Рекомендуется нормализовать дату на границе системы (например, при получении ответа от сервера).


Поведение с пустыми значениями

Значения, которые обрабатываются как отсутствующие:

  • undefined
  • null (если не указано .nullable())
  • '' (пустая строка, если не настроен .transform())

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


Итерация ошибок валидации

При использовании date-схемы возможны следующие типовые ошибки:

  • typeError — невозможно преобразовать значение в дату
  • required — значение отсутствует
  • min — дата меньше допустимого диапазона
  • max — дата больше допустимого диапазона
  • test — нарушение пользовательского правила

Каждая ошибка может быть переопределена через второй аргумент метода.


Комбинирование с другими типами

Date часто используется вместе с:

  • string (на входе API)
  • number (timestamp)
  • object (сложные формы)

Пример нормализации timestamp:

Yup.date().transform((value, originalValue) => {
  return typeof originalValue === 'number'
    ? new Date(originalValue)
    : value;
});

Практика построения устойчивых схем

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

  • явную нормализацию входных данных
  • использование ISO-формата
  • ограничение диапазонов через .min() и .max()
  • контроль временных зон на уровне API
  • разделение ошибок формата и бизнес-логики

Такая комбинация делает поведение схем предсказуемым даже при работе с внешними источниками данных, где формат даты может отличаться.