Обработка дат и времени в схемах валидации требует строгого разделения между входными форматами данных и внутренним представлением. В Zod для этого используются базовые типы, преобразования и уточняющие проверки, позволяющие контролировать как структуру, так и семантику временных значений.
z.date()Тип z.date() предназначен для работы с объектами
Date JavaScript. Он проверяет, что входное значение
является валидным экземпляром Date и не содержит
некорректного состояния.
import { z } from "zod";
const schema = z.date();
Ключевые особенности:
Date-объектыInvalid DateПример поведения:
schema.parse(new Date()); // OK
schema.parse("2025-01-01"); // ошибка
schema.parse(Date.now()); // ошибка
Даже объект Date может быть невалидным. Поэтому часто
добавляется уточнение:
const schema = z.date().refine((val) => !isNaN(val.getTime()));
Такая проверка отсекает случаи Invalid Date, возникающие
при некорректном создании объекта.
z.coerce.date()Для обработки строк и чисел используется принудительное приведение типов:
const schema = z.coerce.date();
Поддерживаемые входные форматы:
Date-объектыПримеры:
schema.parse("2025-01-01T10:00:00Z");
schema.parse(1735689600000);
schema.parse(new Date());
Механизм основан на вызове new Date(value), что
накладывает ограничения на нестандартные форматы.
Для строгой проверки строкового формата используется
z.string().datetime().
const schema = z.string().datetime();
Поддерживается стандарт ISO 8601:
2025-01-01T10:00:00Z2025-01-01T10:00:00+03:00Дополнительные настройки позволяют уточнить поведение:
const schema = z.string().datetime({
offset: true,
precision: 3
});
offset — разрешение временных смещенийprecision — контроль количества миллисекундDate через preprocessДля нестандартных форматов используется z.preprocess,
позволяющий преобразовать вход перед валидацией.
DD.MM.YYYYconst schema = z.preprocess((val) => {
if (typeof val !== "string") return val;
const [day, month, year] = val.split(".");
return new Date(`${year}-${month}-${day}`);
}, z.date());
Такой подход разделяет:
Для значений вида HH:mm применяется комбинированная
схема:
const timeSchema = z.string().regex(/^([01]\d|2[0-3]):([0-5]\d)$/);
Детали:
Для дальнейшей работы часто выполняется трансформация:
const timeSchema = z.string()
.regex(/^([01]\d|2[0-3]):([0-5]\d)$/)
.transform((val) => {
const [hours, minutes] = val.split(":").map(Number);
return { hours, minutes };
});
Результат:
{ hours: 14, minutes: 30 }
Числовые временные метки обрабатываются через z.number()
с последующим преобразованием.
const schema = z.number().int().transform((val) => new Date(val));
Дополнительная проверка:
const schema = z.number()
.int()
.positive()
.transform((val) => new Date(val));
Используемые единицы:
DateЧасто требуется поддержка нескольких форматов одновременно:
const schema = z.union([
z.string().datetime(),
z.coerce.date(),
z.number().int()
]).transform((val) => new Date(val));
Такой подход позволяет принимать:
Date-объектыДля унификации формата используется transform:
const schema = z.coerce.date().transform((date) => ({
iso: date.toISOString(),
timestamp: date.getTime()
}));
Результат фиксирует единое представление вне зависимости от входного формата.
Ограничение временных интервалов реализуется через
refine:
const schema = z.coerce.date().refine((date) => {
const min = new Date("2020-01-01");
const max = new Date("2030-01-01");
return date >= min && date <= max;
});
Применение:
JavaScript Date хранит время в UTC, но отображение
зависит от локальной зоны. В Zod отсутствует встроенная поддержка
полноценной работы с часовыми поясами, поэтому используются внешние
библиотеки или строковые форматы с offset.
Пример валидации строки с временной зоной:
const schema = z.string().datetime({ offset: true });
Форматы:
2025-01-01T10:00:00+05:002025-01-01T05:00:00ZТипичные ошибки:
z.date()Invalid Date после преобразованияNumber.MAX_SAFE_INTEGERЗащитные схемы:
const safeDate = z.coerce.date().refine((d) => !isNaN(d.getTime()));
В структурах данных даты часто комбинируются с другими полями:
const eventSchema = z.object({
title: z.string(),
start: z.coerce.date(),
end: z.coerce.date()
}).refine((data) => data.end > data.start);
Так обеспечивается не только корректность формата, но и логическая целостность временного интервала.
Zod позволяет формировать выходные строки:
const schema = z.coerce.date().transform((date) =>
date.toLocaleDateString("ru-RU")
);
Результат:
01.01.2025Дополнительно возможно формирование структурированных представлений:
.transform((date) => ({
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate()
}));
Работа с датами в Zod опирается на встроенный объект
Date, что накладывает ограничения:
Для сложных сценариев часто требуется дополнительная нормализация перед валидацией.