Минимальные и максимальные даты

Валидация дат в Joi строится вокруг строгого контроля допустимых диапазонов значений. Основной инструмент для работы с датами — Joi.date(), который позволяет задавать ограничения через методы min() и max(). Эти методы определяют нижнюю и верхнюю границы допустимого значения даты, обеспечивая проверку корректности временных интервалов на уровне схемы данных.


Базовая структура проверки даты

Для работы с датами используется базовый тип:

const schema = Joi.date();

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


Минимальная допустимая дата (min)

Метод min() задаёт нижнюю границу допустимого диапазона. Значение, переданное в min, становится включительной границей.

const schema = Joi.date().min('2024-01-01');

В этом случае допустимыми считаются даты, начиная с 1 января 2024 года и позже.

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

  • граница включается в допустимый диапазон;
  • поддерживаются строки, Date-объекты и временные метки;
  • сравнение происходит на уровне UTC;
  • при передаче строки используется парсинг через Date.parse.

Пример использования с объектом Date:

const minDate = new Date('2024-01-01');

const schema = Joi.date().min(minDate);

Максимальная допустимая дата (max)

Метод max() задаёт верхнюю границу диапазона допустимых значений.

const schema = Joi.date().max('2024-12-31');

Здесь валидными считаются все даты до 31 декабря 2024 года включительно.

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

  • верхняя граница включается в допустимый диапазон;
  • поддерживаются те же форматы входных данных, что и в min;
  • применяется строгая проверка по времени, включая часы, минуты и секунды.

Совместное использование min и max

Часто ограничения задаются одновременно, формируя закрытый интервал допустимых значений:

const schema = Joi.date().min('2024-01-01').max('2024-12-31');

Такое определение ограничивает дату диапазоном одного календарного года.


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

Joi сравнивает даты с точностью до миллисекунд. Это означает, что даже при одинаковой календарной дате время может повлиять на результат проверки.

const schema = Joi.date().min('2024-01-01T00:00:00Z');

schema.validate('2024-01-01T00:00:00Z'); // валидно
schema.validate('2023-12-31T23:59:59Z'); // ошибка

При отсутствии временной части в строке используется интерпретация по умолчанию, зависящая от среды выполнения.


Использование относительных дат

В качестве границ допустимо использовать выражения, которые Joi интерпретирует как даты:

const schema = Joi.date().min('now');

Значение 'now' фиксирует нижнюю границу как момент выполнения валидации. Это полезно для запрета прошедших дат, например при планировании событий.

Аналогично возможно комбинирование:

const schema = Joi.date().min('now').max('+1y');

Здесь допустимыми считаются даты от текущего момента до одного года вперёд.


Поведение при ошибках валидации

При выходе значения за пределы заданного диапазона Joi возвращает ошибку с кодом date.min или date.max.

Пример структуры ошибки:

{
  message: '"value" must be greater than or equal to "2024-01-01"',
  type: 'date.min',
  context: {
    limit: '2024-01-01',
    value: '2023-12-31'
  }
}

Для верхней границы используется тип date.max.


Кастомизация сообщений

Сообщения об ошибках можно переопределить через messages():

const schema = Joi.date()
  .min('2024-01-01')
  .messages({
    'date.min': 'Дата не может быть раньше 2024 года'
  });

Это позволяет стандартизировать формат ответов API без обработки ошибок на уровне бизнес-логики.


Влияние временных зон

Joi опирается на объект Date JavaScript, поэтому временные зоны интерпретируются в зависимости от среды выполнения. При работе с ISO-строками рекомендуется явно указывать UTC:

Joi.date().min('2024-01-01T00:00:00Z');

Это снижает риск расхождений при сравнении дат в распределённых системах.


Поведение с числовыми timestamp

Допустимо использование UNIX timestamp (миллисекунды):

const schema = Joi.date().min(1704067200000);

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


Валидация диапазонов в сложных схемах

Ограничения min и max применяются независимо от контекста объекта, но часто используются внутри вложенных структур:

const schema = Joi.object({
  startDate: Joi.date().required(),
  endDate: Joi.date().min(Joi.ref('startDate'))
});

В этом случае endDate должен быть не раньше startDate, что формирует динамическое ограничение на основе значения другого поля.


Комбинация с другими правилами

Методы min и max часто используются вместе с:

  • required() — обязательность поля;
  • iso() — строгий формат ISO 8601;
  • precision() — ограничение точности времени.

Пример комплексной схемы:

const schema = Joi.date()
  .iso()
  .min('2024-01-01')
  .max('2024-12-31')
  .required();

Частые ошибки при использовании границ

Неправильный формат строки

Joi.date().min('01-01-2024'); // может быть интерпретировано некорректно

Корректный вариант — ISO формат:

Joi.date().min('2024-01-01');

Игнорирование временной части

Joi.date().min('2024-01-01');

Такое ограничение может пропускать значения, близкие к границе, но отличающиеся по времени.


Поведение при отсутствии границ

Без min и max дата считается валидной, если она может быть преобразована в корректный объект Date. Это создаёт максимально широкую область допустимых значений и переносит ответственность за ограничения на уровень бизнес-логики.


Роль строгих диапазонов в архитектуре данных

Использование минимальных и максимальных дат в Joi формирует слой первичной защиты данных. Проверка на уровне схемы предотвращает:

  • сохранение дат вне допустимого периода;
  • ошибки планирования событий;
  • некорректные временные диапазоны в API;
  • рассинхронизацию между клиентом и сервером.

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