Валидация дат в 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 работает в локальном часовом поясе
окружения, что может приводить к неожиданным результатам при сравнении
дат:
Пример проблемы:
new Date('2026-05-10')
Интерпретация зависит от окружения и может смещаться относительно UTC.
Для более предсказуемой работы с датами часто используют внешние библиотеки.
import dayjs from 'dayjs';
const schema = Yup.object({
eventDate: Yup.date().min(
dayjs().toDate(),
'Дата должна быть в будущем'
)
});
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.