Проверка относительно текущей даты

Валидация дат в Yup строится вокруг базового типа Yup.date(), который позволяет задавать ограничения на допустимые значения, включая сравнение с фиксированными датами и динамическими значениями, такими как текущее время выполнения программы. При работе с текущей датой важно учитывать, что значение вычисляется в момент валидации, а не на этапе объявления схемы.


Базовая схема работы с Yup.date()

Типичная схема валидации даты начинается с определения поля как даты:

import * as Yup from 'yup';

const schema = Yup.object({
  date: Yup.date()
});

По умолчанию Yup пытается привести входное значение к объекту Date. Если преобразование невозможно, возвращается ошибка валидации.


Сравнение с текущей датой

Одной из наиболее частых задач является проверка того, что дата находится относительно текущего момента — раньше или позже.

Проверка на дату в будущем

const schema = Yup.object({
  eventDate: Yup.date()
    .min(new Date(), 'Дата должна быть в будущем')
});

Здесь используется new Date() как нижняя граница. Однако важно учитывать, что это значение фиксируется в момент создания схемы. Если схема создаётся один раз при загрузке модуля, то «текущая дата» перестаёт быть актуальной при длительном выполнении приложения.


Динамическое вычисление текущей даты

Чтобы избежать фиксации времени, используется функция, возвращающая актуальное значение:

const schema = Yup.object({
  eventDate: Yup.date()
    .min(() => new Date(), 'Дата должна быть в будущем')
});

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


Проверка даты рождения (ограничение в прошлом)

Распространённый сценарий — проверка, что дата рождения не может быть в будущем:

const schema = Yup.object({
  birthDate: Yup.date()
    .max(new Date(), 'Дата рождения не может быть в будущем')
});

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

const schema = Yup.object({
  birthDate: Yup.date()
    .max(new Date(Date.now() - 1000 * 60 * 60 * 24), 'Некорректная дата')
});

Однако такое решение остаётся грубым, так как не учитывает точный возраст.


Проверка возраста через вычисление границы

Более корректный подход — вычисление даты, соответствующей минимальному возрасту:

const MIN_AGE = 18;

const schema = Yup.object({
  birthDate: Yup.date()
    .max(() => {
      const today = new Date();
      return new Date(
        today.getFullYear() - MIN_AGE,
        today.getMonth(),
        today.getDate()
      );
    }, 'Возраст должен быть не менее 18 лет')
});

Здесь создаётся динамическая граница, основанная на текущей дате.


Использование кастомной проверки test

Когда логика выходит за рамки min и max, применяется метод test:

const schema = Yup.object({
  eventDate: Yup.date().test(
    'not-in-past',
    'Дата не может быть в прошлом',
    function (value) {
      if (!value) return false;
      return value.getTime() > Date.now();
    }
  )
});

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


Сравнение с другими полями формы

Yup позволяет сравнивать даты между собой через контекст объекта:

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

Для добавления проверки относительно текущей даты комбинируется ref и test:

const schema = Yup.object({
  startDate: Yup.date().min(new Date(), 'Дата начала должна быть в будущем'),
  endDate: Yup.date().min(Yup.ref('startDate'))
});

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

JavaScript Date работает в локальном часовом поясе окружения, что может приводить к неожиданным результатам при сравнении дат:

  • сервер может использовать UTC
  • браузер — локальное время пользователя

Пример проблемы:

new Date('2026-05-10')

Интерпретация зависит от окружения и может смещаться относительно UTC.


Интеграция с dayjs и date-fns

Для более предсказуемой работы с датами часто используют внешние библиотеки.

Использование dayjs

import dayjs from 'dayjs';

const schema = Yup.object({
  eventDate: Yup.date().min(
    dayjs().toDate(),
    'Дата должна быть в будущем'
  )
});

Использование date-fns

import { isAfter } from 'date-fns';

const schema = Yup.object({
  eventDate: Yup.date().test(
    'is-future',
    'Дата должна быть в будущем',
    value => value && isAfter(value, new Date())
  )
});

Частые ошибки при сравнении с текущей датой

1. Фиксация new Date() при создании схемы

Yup.date().min(new Date()) // значение устаревает

2. Некорректная работа с временем суток

Сравнение дат без обнуления времени приводит к неожиданным результатам:

const today = new Date();
today.setHours(0, 0, 0, 0);

3. Различие между строкой и объектом Date

Yup пытается привести строку к Date, но формат может влиять на результат.


Сценарии использования проверки относительно текущей даты

  • ограничение регистрации по возрасту
  • проверка срока действия документов
  • контроль будущих событий (ивенты, бронирования)
  • дедлайны и сроки выполнения задач
  • запрет на выбор прошедших дат в интерфейсе календаря

Работа с миллисекундами для точного сравнения

Для строгой логики используется сравнение через getTime():

const schema = Yup.object({
  deadline: Yup.date().test(
    'future-deadline',
    'Срок должен быть в будущем',
    value => value && value.getTime() > Date.now()
  )
});

Такой подход исключает влияние форматирования и временных зон на уровне объекта Date.