@MinDate, @MaxDate

Декоратор @MinDate проверяет, что значение даты не меньше указанного минимального значения. Проверка применяется к объектам Date и используется для ограничения диапазона допустимых дат.

Наиболее распространённые сценарии:

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

Базовый синтаксис

import { MinDate } from 'class-validator'

class EventDto {
  @MinDate(new Date())
  eventDate: Date
}

В этом примере поле eventDate должно содержать дату не раньше текущего момента.

Если передать дату из прошлого, валидация завершится ошибкой.


Принцип работы

@MinDate сравнивает значение поля с указанной датой:

value >= minDate

Если условие истинно — валидация проходит успешно.


Простая проверка минимальной даты

import { validate } from 'class-validator'
import { MinDate } from 'class-validator'

class UserDto {
  @MinDate(new Date('2025-01-01'))
  registrationDate: Date
}

async function run() {
  const dto = new UserDto()

  dto.registrationDate = new Date('2024-05-10')

  const errors = await validate(dto)

  console.log(errors)
}

run()

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


Использование с текущей датой

Одна из самых популярных задач — запрет дат в прошлом.

class BookingDto {
  @MinDate(new Date())
  bookingDate: Date
}

Такой подход имеет важную особенность.

Важный нюанс

@MinDate(new Date())

new Date() вызывается в момент создания класса, а не во время валидации.

Это означает, что минимальная дата фиксируется один раз.

Например:

class ExampleDto {
  @MinDate(new Date())
  date: Date
}

Если сервер работает несколько суток без перезапуска, минимальная дата останется старой.


Динамическая дата через функцию

Для динамических значений используется функция.

class BookingDto {
  @MinDate(() => new Date())
  bookingDate: Date
}

Теперь дата вычисляется во время каждой проверки.

Это правильный способ проверки текущего времени.


Проверка даты рождения

class PersonDto {
  @MinDate(new Date('1900-01-01'))
  birthDate: Date
}

Подобная проверка предотвращает ввод некорректно старых дат.


Совместное использование с @IsDate

@MinDate не проверяет тип значения. Декоратор лишь сравнивает даты.

Поэтому обычно используется комбинация:

import {
  IsDate,
  MinDate
} from 'class-validator'

class TaskDto {
  @IsDate()
  @MinDate(() => new Date())
  deadline: Date
}

Проблемы со строками

Частая ошибка — передача строк вместо объектов Date.

dto.deadline = '2026-01-01'

@IsDate() не пропустит такое значение.


Преобразование строк в Date

При использовании class-transformer можно автоматически преобразовывать строки.

import { Type } from 'class-transformer'
import { IsDate, MinDate } from 'class-validator'

class EventDto {
  @Type(() => Date)
  @IsDate()
  @MinDate(() => new Date())
  date: Date
}

Теперь строка:

{
  "date": "2026-10-01"
}

будет преобразована в объект Date.


Проверка даты начала мероприятия

class ConferenceDto {
  @Type(() => Date)
  @IsDate()
  @MinDate(() => new Date())
  startDate: Date
}

Такой подход часто используется в:

  • системах бронирования;
  • CRM;
  • календарях;
  • сервисах видеоконференций.

Использование собственного сообщения

class BookingDto {
  @MinDate(() => new Date(), {
    message: 'Дата бронирования не может быть в прошлом'
  })
  bookingDate: Date
}

Использование функции сообщения

class PaymentDto {
  @MinDate(() => new Date(), {
    message: (args) => {
      return `Дата ${args.value} недопустима`
    }
  })
  paymentDate: Date
}

Проверка нескольких полей

class SubscriptionDto {
  @Type(() => Date)
  @IsDate()
  @MinDate(() => new Date())
  startDate: Date

  @Type(() => Date)
  @IsDate()
  @MinDate(() => new Date())
  renewalDate: Date
}

Проверка nullable-значений

Если поле необязательно, применяется @IsOptional.

import {
  IsOptional,
  IsDate,
  MinDate
} from 'class-validator'

class UpdateDto {
  @IsOptional()
  @IsDate()
  @MinDate(() => new Date())
  publishDate?: Date
}

Поведение с null

dto.publishDate = null

Если отсутствует @IsOptional(), валидация завершится ошибкой.


Проверка в NestJS

DTO:

import {
  IsDate,
  MinDate
} from 'class-validator'

import { Type } from 'class-transformer'

export class CreateEventDto {
  @Type(() => Date)
  @IsDate()
  @MinDate(() => new Date())
  eventDate: Date
}

Контроллер:

@Post()
create(@Body() dto: CreateEventDto) {
  return dto
}

Ошибка валидации

Пример ответа:

{
  "statusCode": 400,
  "message": [
    "eventDate минимально допустимая дата ..."
  ],
  "error": "Bad Request"
}

Декоратор @MaxDate

@MaxDate выполняет противоположную задачу — проверяет, что дата не превышает установленный максимум.

Условие проверки:

value <= maxDate

Базовый пример

import { MaxDate } from 'class-validator'

class ArchiveDto {
  @MaxDate(new Date())
  archivedAt: Date
}

Поле не может содержать дату из будущего.


Проверка даты рождения

Один из самых частых сценариев:

class UserDto {
  @MaxDate(new Date())
  birthDate: Date
}

Дата рождения не должна быть больше текущей даты.


Динамический максимум

Как и в случае с @MinDate, рекомендуется использовать функцию.

class UserDto {
  @MaxDate(() => new Date())
  birthDate: Date
}

Ограничение периода

class ReportDto {
  @MaxDate(new Date('2030-01-01'))
  reportDate: Date
}

Проверка исторических данных

class HistoryDto {
  @Type(() => Date)
  @IsDate()
  @MaxDate(() => new Date())
  eventDate: Date
}

Такой подход предотвращает появление будущих событий в архиве.


Комбинация @MinDate и @MaxDate

Оба декоратора часто используются вместе.

class VacationDto {
  @Type(() => Date)
  @IsDate()
  @MinDate(new Date('2025-01-01'))
  @MaxDate(new Date('2025-12-31'))
  vacationDate: Date
}

Теперь допустимы только даты внутри 2025 года.


Проверка диапазона дат

class SeasonDto {
  @Type(() => Date)
  @IsDate()
  @MinDate(new Date('2025-06-01'))
  @MaxDate(new Date('2025-08-31'))
  date: Date
}

Валидация дедлайна

class TaskDto {
  @Type(() => Date)
  @IsDate()
  @MinDate(() => new Date())
  @MaxDate(new Date('2030-01-01'))
  deadline: Date
}

Здесь:

  • дедлайн не может быть в прошлом;
  • дедлайн ограничен верхней датой.

Пользовательские сообщения

class UploadDto {
  @MaxDate(() => new Date(), {
    message: 'Дата загрузки не может быть из будущего'
  })
  uploadedAt: Date
}

Работа с часовыми поясами

Date в JavaScript хранит время в UTC.

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

new Date('2025-01-01')

может интерпретироваться по-разному в зависимости от часового пояса.


Потенциальная проблема

@MaxDate(new Date('2025-01-01'))

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


Рекомендации по работе с timezone

Использование ISO-формата

new Date('2025-01-01T00:00:00Z')

Явное указание UTC

new Date(Date.UTC(2025, 0, 1))

Нормализация времени

Иногда необходимо обнулять часы:

const date = new Date()

date.setHours(0, 0, 0, 0)

Проверка только даты без времени

@MinDate и @MaxDate сравнивают полные timestamp-значения.

Это означает:

2025-01-01 10:00

и

2025-01-01 20:00

— разные значения.


Пример нормализации

function normalizeDate(date: Date) {
  const result = new Date(date)

  result.setHours(0, 0, 0, 0)

  return result
}

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

class ExampleDto {
  @MinDate(normalizeDate(new Date()))
  date: Date
}

Проверка массива дат

import {
  IsArray,
  IsDate,
  MinDate
} from 'class-validator'

class CalendarDto {
  @IsArray()
  @IsDate({ each: true })
  @MinDate(() => new Date(), {
    each: true
  })
  dates: Date[]
}

Валидация расписания

class ScheduleDto {
  @IsArray()
  @Type(() => Date)
  @IsDate({ each: true })
  @MinDate(() => new Date(), {
    each: true
  })
  events: Date[]
}

Проверка дат в вложенных объектах

import {
  ValidateNested,
  IsDate,
  MinDate
} from 'class-validator'

import { Type } from 'class-transformer'

class EventItemDto {
  @Type(() => Date)
  @IsDate()
  @MinDate(() => new Date())
  date: Date
}

class CalendarDto {
  @ValidateNested({ each: true })
  @Type(() => EventItemDto)
  items: EventItemDto[]
}

Использование групп валидации

class PublishDto {
  @MinDate(() => new Date(), {
    groups: ['create']
  })
  publishDate: Date
}

Проверка:

validate(dto, {
  groups: ['create']
})

Условная валидация

import {
  ValidateIf,
  MinDate
} from 'class-validator'

class EventDto {
  isPublished: boolean

  @ValidateIf(o => o.isPublished)
  @MinDate(() => new Date())
  publishDate: Date
}

Типичные ошибки

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

publishDate: '2025-01-01'

Отсутствие @Type(() => Date)

Без трансформации строки не превращаются в объекты даты.


Использование new Date() без функции

@MinDate(new Date())

Фиксирует дату при старте приложения.


Игнорирование timezone

Особенно критично для международных систем.


Проверка только даты без времени

@MinDate и @MaxDate всегда учитывают время.


Практический пример полноценного DTO

import {
  IsDate,
  MinDate,
  MaxDate,
  IsOptional
} from 'class-validator'

import { Type } from 'class-transformer'

export class CreateWebinarDto {
  @Type(() => Date)
  @IsDate()
  @MinDate(() => new Date(), {
    message: 'Дата начала не может быть в прошлом'
  })
  startDate: Date

  @Type(() => Date)
  @IsDate()
  @MaxDate(new Date('2035-01-01'), {
    message: 'Дата окончания слишком большая'
  })
  endDate: Date

  @IsOptional()
  @Type(() => Date)
  @IsDate()
  @MaxDate(() => new Date())
  createdAt?: Date
}