Работа с датами в Joi строится вокруг метода Joi.date(),
который определяет поле как значение типа Date и предоставляет набор
инструментов для строгой и гибкой валидации временных данных. Валидация
дат в прикладных задачах часто связана с проверкой диапазонов, форматов,
временных ограничений и преобразований входных значений, поступающих из
HTTP-запросов или других внешних источников.
Базовое определение даты выглядит следующим образом:
const schema = Joi.object({
createdAt: Joi.date()
});
Любое значение, которое может быть интерпретировано как дата JavaScript, будет преобразовано и проверено на корректность. Входные строки типа ISO, timestamp или Date-объекты проходят нормализацию.
Joi.date() по умолчанию выполняет преобразование входных
значений. Это означает, что строки и числа могут автоматически
интерпретироваться как даты.
Поддерживаются следующие типы входных данных:
Пример:
const schema = Joi.object({
createdAt: Joi.date()
});
schema.validate({
createdAt: '2024-01-01T10:00:00.000Z'
});
Также допустимы числовые значения:
schema.validate({
createdAt: 1704103200000
});
Если требуется запрет автоматического преобразования, используется строгий режим:
Joi.date().strict()
В строгом режиме допустимы только Date объекты, без
преобразования строк и чисел.
Ограничение диапазона времени реализуется через методы
min() и max().
const schema = Joi.object({
createdAt: Joi.date().min('2020-01-01')
});
Значение должно быть не ранее указанной даты.
const schema = Joi.object({
createdAt: Joi.date().max('2025-12-31')
});
Допускается также использование Date объектов:
const minDate = new Date('2020-01-01');
Joi.date().min(minDate);
Joi поддерживает относительные ограничения на основе текущего времени:
Joi.date().less('now')
Joi.date().greater('now')
Эти проверки часто применяются для событий:
Для контроля формата используется iso():
Joi.date().iso()
Это ограничивает вход только ISO 8601 строками.
Пример допустимого значения:
2024-05-10T12:30:00.000Z
Любые нестандартные строки будут отклонены.
Иногда требуется принимать только числовой Unix timestamp:
Joi.date().timestamp()
Можно указать единицы измерения:
Joi.date().timestamp('unix') // секунды
Joi.date().timestamp('javascript') // миллисекунды
Это важно при интеграции с API, где формат времени фиксирован.
Для автоматического заполнения даты применяется
default():
Joi.date().default(Date.now)
Важно, что функция передаётся без вызова, чтобы значение вычислялось при каждой валидации.
Также возможно использование фиксированной даты:
Joi.date().default('2020-01-01')
Как и для других типов, применяются:
Joi.date().required()
Joi.date().optional()
Joi.date().allow(null)
Пример комбинированной схемы:
Joi.date().optional().allow(null)
Это позволяет явно контролировать отсутствие даты.
Метод invalid() используется для исключения конкретных
дат:
Joi.date().invalid('2024-01-01')
Можно комбинировать несколько значений:
Joi.date().invalid('2024-01-01', '2024-12-31')
Для дат часто требуется кастомизация сообщений:
Joi.date().messages({
'date.base': 'Значение должно быть датой',
'date.min': 'Дата слишком ранняя',
'date.max': 'Дата превышает допустимый предел'
});
Каждый тип ошибки связан с конкретным правилом валидации.
Joi позволяет строить сложные правила:
const schema = Joi.object({
startDate: Joi.date().required().min('2020-01-01'),
endDate: Joi.date().greater(Joi.ref('startDate'))
});
Здесь реализуется зависимость между полями объекта: конечная дата должна быть позже начальной.
Joi.ref() позволяет сравнивать даты внутри объекта:
Joi.date().greater(Joi.ref('createdAt'))
Это особенно важно для:
При интеграции с HTTP API даты часто приходят в строковом виде. Типичная схема запроса:
const schema = Joi.object({
userId: Joi.number().required(),
createdAt: Joi.date().iso().required(),
updatedAt: Joi.date().optional()
});
Такой подход обеспечивает единообразие входных данных и предотвращает ошибки парсинга.
Joi приводит даты к стандартному виду Date объекта. Это
упрощает дальнейшую обработку:
const result = schema.validate({
createdAt: '2024-01-01T00:00:00Z'
});
result.value.createdAt instanceof Date; // true
Таким образом, после валидации данные уже готовы к использованию в логике приложения без дополнительного парсинга.
Частая задача — проверка интервала:
const schema = Joi.object({
start: Joi.date().required(),
end: Joi.date().required().greater(Joi.ref('start'))
});
При необходимости допускается равенство:
Joi.date().min(Joi.ref('start'))
Для событий с ограничением на ближайший период:
Joi.date().max('now').min('2023-01-01')
Это ограничивает дату диапазоном между прошлым и текущим моментом.
Joi не выполняет сложную обработку таймзон, так как использует
стандартный объект Date. Входные ISO строки с таймзоной
корректно приводятся к UTC:
Joi.date().iso()
Пример:
2024-05-10T12:00:00+03:00
будет нормализован в UTC-эквивалент.
В больших объектах даты часто комбинируются с другими типами:
const schema = Joi.object({
id: Joi.string().uuid().required(),
createdAt: Joi.date().default(Date.now),
updatedAt: Joi.date().optional(),
deletedAt: Joi.date().allow(null)
});
Такая структура типична для сущностей с жизненным циклом.
Joi позволяет проверять коллекции:
Joi.array().items(Joi.date().iso())
Это используется для:
Если входное значение невозможно интерпретировать как дату,
возвращается ошибка типа date.base. Это означает, что
значение не соответствует допустимому формату даты и не может быть
преобразовано даже в рамках гибкого режима.
Использование Joi.date() обычно включает комбинацию:
min, max)greater,
less)iso, timestamp)Joi.ref)