date-time-validation
Validation constraints for date/time objects.
Modules
Because this repository contains a lot of constraints, and each applies to several date/time object types, it is split into several modules. This allows you to only use those modules you need without getting a single, large dependency.
The following sections each describe a module. Most of these modules validate only a part of the value. Because the exact date and time depends on the time zone, each annotation in these modules has an optional zoneId
parameter. This can have the following values:
system
(default): the system time zone, as returned byZoneId.systemDefault()
, should be used.provided
: the time zone or offset information from the actual value should be used.- A value that is valid according to
ZoneId.of
for an explicit time zone.
date-time-validation
Validation constraints for date/time objects that validate entire values. These validate the following, where object
is the object to be validated, moment
is the value specified in the constraint, and duration
is a ISO 8601 duration:
Constraint | Meaning |
---|---|
After | object > moment |
NotAfter | object <= moment |
MinAfter | object >= moment + duration |
MaxAfter | object <= moment + duration |
Before | object < moment |
NotBefore | object >= moment |
MinBefore | object <= moment - duration |
MaxBefore | object >= moment - duration |
The format of moment
and duration
depends on the type to validate:
- For classes from the
java.time
package,moment
must be valid according to the class'parse
method. - For
Date
,moment
must be valid according toInstant.parse
. - For
Calendar
,moment
must be valid according toZonedDateTime.parse
. duration
may not contain parts that are not present in the type. For instance, forLocalDate
duration
may not contain any time elements, forLocalTime
it may not contain any date elements, forYearMonth
it may only contain year and/or month elements, etc.
In addition, for all annotations the moment
can be defined as literal value now
to indicate the current date/time must be used.
These annotations apply to the following types:
Type | After | NotAfter | MinAfter | MaxAfter | Before | NotBefore | MinBefore | MaxBefore |
---|---|---|---|---|---|---|---|---|
Date | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Calendar | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
DayOfWeek | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
Instant | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
LocalDate | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
LocalDateTime | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
LocalTime | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Month | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
MonthDay1 | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ |
OffsetDateTime | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
OffsetTime | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Year | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
YearMonth | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
ZonedDateTime | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
1: MinAfter
, MaxAfter
, MinBefore
and MaxBefore
cannot be applied to MonthDay because “it is not possible to define whether February 29th is valid or not without external information”. This makes it impossible to apply durations to MonthDay
moments.
date-validation
Validation constraints for date/time objects that validate only the date part. These work just like the constraints of the date-time-validation
module, except they ignore any time part. The moment
must be now
or valid according to LocalDate.parse
, and the duration
may not contain any time elements.
These annotations apply to the following types:
Type | DateAfter | DateNotAfter | DateMinAfter | DateMaxAfter | DateBefore | DateNotBefore | DateMinBefore | DateMaxBefore |
---|---|---|---|---|---|---|---|---|
Date1 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Calendar | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
DayOfWeek | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
Instant1 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
LocalDate2 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
LocalDateTime3 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
LocalTime | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
Month | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
MonthDay | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
OffsetDateTime | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
OffsetTime | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
Year | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
YearMonth | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
ZonedDateTime | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
1: because the type has no time zone information, the zoneId
may not be defined as provided
.
2: can be validated with annotations from date-time-validation
.
3: because no time zone is applicable for the type, the zoneId
must be defined as system
. Since this is the default, the zoneId
parameter can simply be omitted.
time-validation
Validation constraints for date/time objects that validate only the time part. These work just like the constraints of date-time-validation
module, except they ignore any date part. The moment
must be now
or valid according to LocalTime.parse
, and the duration
may not contain any date elements.
These annotations apply to the following types:
Type | TimeAfter | TimeNotAfter | TimeMinAfter | TimeMaxAfter | TimeBefore | TimeNotBefore | TimeMinBefore | TimeMaxBefore |
---|---|---|---|---|---|---|---|---|
Date1 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Calendar | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
DayOfWeek | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
Instant1 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
LocalDate | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
LocalDateTime2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
LocalTime3 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
Month | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
MonthDay | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
OffsetDateTime | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
OffsetTime3 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
Year | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
YearMonth | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
ZonedDateTime | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
1: because the type has no time zone information, the zoneId
may not be defined as provided
.
2: because no time zone is applicable for the type, the zoneId
must be defined as system
. Since this is the default, the zoneId
parameter can simply be omitted.
3: can be validated with annotations from date-time-validation
.
year-month-validation
Validation constraints for date/time objects that validate only the year and month. These work just like the constraints of the date-time-validation
module, except they ignore the day of the month and any time part. The moment
must be now
or valid according to YearMonth.parse
, and the duration
may only contain year and month elements.
These annotations apply to the following types:
Type | YearMonthAfter | YearMonthNotAfter | YearMonthMinAfter | YearMonthMaxAfter | YearMonthBefore | YearMonthNotBefore | YearMonthMinBefore | YearMonthMaxBefore |
---|---|---|---|---|---|---|---|---|
Date1 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Calendar | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
DayOfWeek | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
Instant1 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
LocalDate2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
LocalDateTime2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
LocalTime | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
Month | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
MonthDay | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
OffsetDateTime | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
OffsetTime | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
Year | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
YearMonth3 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
ZonedDateTime | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
1: because the type has no time zone information, the zoneId
may not be defined as provided
.
2: because no time zone is applicable for the type, the zoneId
must be defined as system
. Since this is the default, the zoneId
parameter can simply be omitted.
3: can be validated with annotations from date-time-validation
.
year-validation
Validation constraints for date/time objects that validate only the year. These work just like the constraints of the date-time-validation
module, except they ignore the month, the day of the month and any time part. The moment
must be now
or valid according to Year.parse
, and the duration
(renamed to years
) must be specified as a number of years only. The latter prevents having to write "P1Y"
instead of just 1
.
These annotations apply to the following types:
Type | YearAfter | YearNotAfter | YearMinAfter | YearMaxAfter | YearBefore | YearNotBefore | YearMinBefore | YearMaxBefore |
---|---|---|---|---|---|---|---|---|
Date1 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Calendar | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
DayOfWeek | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
Instant1 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
LocalDate2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
LocalDateTime2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
LocalTime | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
Month | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
MonthDay | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
OffsetDateTime | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
OffsetTime | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
Year3 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
YearMonth2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
ZonedDateTime | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
1: because the type has no time zone information, the zoneId
may not be defined as provided
.
2: because no time zone is applicable for the type, the zoneId
must be defined as system
. Since this is the default, the zoneId
parameter can simply be omitted.
3: can be validated with annotations from date-time-validation
.
month-validation
Validation constraints for date/time objects that validate only the month. These validate the following, where object
is the object to be validated, and value
is the value specified in the constraint:
Constraint | Meaning |
---|---|
MonthIs | object.month == value |
MonthIn | value.contains(object.month) |
MonthNotIn | !value.contains(object.month) |
These annotations apply to the following types:
Type | MonthIs | MonthIn | MonthNotIn |
---|---|---|---|
Date1 | ✅ | ✅ | ✅ |
Calendar | ✅ | ✅ | ✅ |
DayOfWeek | ❌ | ❌ | ❌ |
Instant1 | ✅ | ✅ | ✅ |
LocalDate2 | ✅ | ✅ | ✅ |
LocalDateTime2 | ✅ | ✅ | ✅ |
LocalTime | ❌ | ❌ | ❌ |
Month2 | ✅ | ✅ | ✅ |
MonthDay2 | ✅ | ✅ | ✅ |
OffsetDateTime | ✅ | ✅ | ✅ |
OffsetTime | ❌ | ❌ | ❌ |
Year | ❌ | ❌ | ❌ |
YearMonth2 | ✅ | ✅ | ✅ |
ZonedDateTime | ✅ | ✅ | ✅ |
1: because the type has no time zone information, the zoneId
may not be defined as provided
.
2: because no time zone is applicable for the type, the zoneId
must be defined as system
. Since this is the default, the zoneId
parameter can simply be omitted.
year-month-validation vs month-validation
year-month-validation
validates the combination of the year and the month. This allows it to be used for cases like credit card validation. month-validation
on the other hand ignores the year.
day-of-week-validation
Validation constraints for date/time objects that validate only the day of the week. These validate the following, where object
is the object to be validated, and value
is the value specified in the constraint:
Constraint | Meaning |
---|---|
DayOfWeekIs | object.dayOfWeek == value |
DayOfWeekIn | value.contains(object.dayOfWeek) |
DayOfWeekNotIn | !value.contains(object.dayOfWeek) |
Note that days of the week are ordered from Monday until Sunday.
These annotations apply to the following types:
Type | DayOfWeekIs | DayOfWeekIn | DayOfWeekNotIn |
---|---|---|---|
Date1 | ✅ | ✅ | ✅ |
Calendar | ✅ | ✅ | ✅ |
Instant1 | ✅ | ✅ | ✅ |
LocalDate2 | ✅ | ✅ | ✅ |
DayOfWeek2 | ✅ | ✅ | ✅ |
LocalDateTime2 | ✅ | ✅ | ✅ |
LocalTime | ❌ | ❌ | ❌ |
Month | ❌ | ❌ | ❌ |
MonthDay | ❌ | ❌ | ❌ |
OffsetDateTime | ✅ | ✅ | ✅ |
OffsetTime | ❌ | ❌ | ❌ |
Year | ❌ | ❌ | ❌ |
YearMonth | ❌ | ❌ | ❌ |
ZonedDateTime | ✅ | ✅ | ✅ |
1: because the type has no time zone information, the zoneId
may not be defined as provided
.
2: because no time zone is applicable for the type, the zoneId
must be defined as system
. Since this is the default, the zoneId
parameter can simply be omitted.
day-of-month-validation
Validation constraints for date/time objects that validate only the day of the month. These validate the following, where object
is the object to be validated, and value
is the value specified in the constraint:
Constraint | Meaning |
---|---|
DayOfMonthIs | object.dayOfMonth == value |
DayOfMonthIn | value.contains(object.dayOfMonth) |
DayOfMonthNotIn | !value.contains(object.dayOfMonth) |
LastDayOfMonth | object.dayOfMonth == object.month.lastDay |
These annotations apply to the following types:
Type | DayOfMonthIs | DayOfMonthIn | DayOfMonthNotIn | LastDayOfMonth |
---|---|---|---|---|
Date1 | ✅ | ✅ | ✅ | ✅ |
Calendar | ✅ | ✅ | ✅ | ✅ |
DayOfWeek | ❌ | ❌ | ❌ | ❌ |
Instant1 | ✅ | ✅ | ✅ | ✅ |
LocalDate2 | ✅ | ✅ | ✅ | ✅ |
LocalDateTime2 | ✅ | ✅ | ✅ | ✅ |
LocalTime | ❌ | ❌ | ❌ | ❌ |
Month | ❌ | ❌ | ❌ | ❌ |
MonthDay3 | ✅ | ✅ | ✅ | ❌ |
OffsetDateTime | ✅ | ✅ | ✅ | ✅ |
OffsetTime | ❌ | ❌ | ❌ | ❌ |
Year | ❌ | ❌ | ❌ | ❌ |
YearMonth | ❌ | ❌ | ❌ | ❌ |
ZonedDateTime | ✅ | ✅ | ✅ | ✅ |
1: because the type has no time zone information, the zoneId
may not be defined as provided
.
2: because no time zone is applicable for the type, the zoneId
must be defined as system
. Since this is the default, the zoneId
parameter can simply be omitted.
3: LastDayOfMonth
cannot be applied to MonthDay because “it is not possible to define whether February 29th is valid or not without external information”. This makes it impossible to determine whether or not February 28th is the last day of the month or not.
hour-validation
Validation constraints for date/time objects that validate only the hour. These validate the following, where object
is the object to be validated, and value
is the value specified in the constraint:
Constraint | Meaning |
---|---|
HourIs | object.hour == value |
HourIn | value.contains(object.hour) |
HourNotIn | !value.contains(object.hour) |
These annotations apply to the following types:
Type | HourIs | HourIn | HourNotIn |
---|---|---|---|
Date1 | ✅ | ✅ | ✅ |
Calendar | ✅ | ✅ | ✅ |
DayOfWeek | ❌ | ❌ | ❌ |
Instant1 | ✅ | ✅ | ✅ |
LocalDate | ❌ | ❌ | ❌ |
LocalDateTime2 | ✅ | ✅ | ✅ |
LocalTime2 | ✅ | ✅ | ✅ |
Month | ❌ | ❌ | ❌ |
MonthDay | ❌ | ❌ | ❌ |
OffsetDateTime | ✅ | ✅ | ✅ |
OffsetTime | ✅ | ✅ | ✅ |
Year | ❌ | ❌ | ❌ |
YearMonth | ❌ | ❌ | ❌ |
ZonedDateTime | ✅ | ✅ | ✅ |
1: because the type has no time zone information, the zoneId
may not be defined as provided
.
2: because no time zone is applicable for the type, the zoneId
must be defined as system
. Since this is the default, the zoneId
parameter can simply be omitted.
minute-validation
Validation constraints for date/time objects that validate only the minute. These validate the following, where object
is the object to be validated, and value
is the value specified in the constraint:
Constraint | Meaning |
---|---|
MinuteIs | object.minute == value |
MinuteIn | value.contains(object.minute) |
MinuteNotIn | !value.contains(object.minute) |
These annotations apply to the following types:
Type | MinuteIs | MinuteIn | MinuteNotIn |
---|---|---|---|
Date1 | ✅ | ✅ | ✅ |
Calendar | ✅ | ✅ | ✅ |
DayOfWeek | ❌ | ❌ | ❌ |
Instant1 | ✅ | ✅ | ✅ |
LocalDate | ❌ | ❌ | ❌ |
LocalDateTime2 | ✅ | ✅ | ✅ |
LocalTime2 | ✅ | ✅ | ✅ |
Month | ❌ | ❌ | ❌ |
MonthDay | ❌ | ❌ | ❌ |
OffsetDateTime | ✅ | ✅ | ✅ |
OffsetTime | ✅ | ✅ | ✅ |
Year | ❌ | ❌ | ❌ |
YearMonth | ❌ | ❌ | ❌ |
ZonedDateTime | ✅ | ✅ | ✅ |
1: because the type has no time zone information, the zoneId
may not be defined as provided
.
2: because no time zone is applicable for the type, the zoneId
must be defined as system
. Since this is the default, the zoneId
parameter can simply be omitted.
time-precision-validation
Validation constraints for date/time objects that validate only the precision of the time part. These validate the following, where object
is the object to be validated, and value
is the value specified in the constraint:
Constraint | Meaning |
---|---|
MinutePrecision | object.second == 0 && object.nanosecond == 0 |
SecondPrecision | object.nanosecond == 0 |
MillisecondPrecision | object.nanosecond % 1000_000 == 0 |
MicrosecondPrecision | object.nanosecond % 1000 == 0 |
These annotations apply to the following types:
Type | MinutePrecision | SecondPrecision | MillisecondPrecision | MicrosecondPrecision |
---|---|---|---|---|
Date1 | ✅ | ✅ | ❌ | ❌ |
Calendar | ✅ | ✅ | ❌ | ❌ |
DayOfWeek | ❌ | ❌ | ❌ | ❌ |
Instant1 | ✅ | ✅ | ✅ | ✅ |
LocalDate | ❌ | ❌ | ❌ | ❌ |
LocalDateTime | ✅ | ✅ | ✅ | ✅ |
LocalTime | ✅ | ✅ | ✅ | ✅ |
Month | ❌ | ❌ | ❌ | ❌ |
MonthDay | ❌ | ❌ | ❌ | ❌ |
OffsetDateTime | ✅ | ✅ | ✅ | ✅ |
OffsetTime | ✅ | ✅ | ✅ | ✅ |
Year | ❌ | ❌ | ❌ | ❌ |
YearMonth | ❌ | ❌ | ❌ | ❌ |
ZonedDateTime | ✅ | ✅ | ✅ | ✅ |
1: to be able to determine the second, the UTC zone is applied.
Examples
To specify that a date of birth must be at least 18 years in the past:
@MinBefore(moment = "now", duration = "P18Y")
LocalDate dateOfBirth;
To specify that a credit card must not have expired:
@NotBefore(moment = "now")
YearMonth expiryDate;
To specify that a credit card must not expire within the next 6 months:
@MinAfter(duration = "P6M", moment = "now")
YearMonth expiryDate;
To specify that a date must be next month or later, where the day of the month is irrelevant:
@YearMonthMinAfter(duration = "P1M", moment = "now")
LocalDate date;
To specify that a date must be next year or later, where the actual date is irrelevant:
@YearMinAfter(years = 1, moment = "now")
// or @YearAfter(moment = "now")
LocalDate date;
To specify that a date/time object like ZonedDateTime
must be on a weekday between 9:00 and 18:00 (exclusive), at 15 minute intervals, and not between 12:00 and 13:00 (exclusive):
@DayOfWeekIn({ MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY })
@TimeNotBefore(moment = "09:00:00")
@TimeBefore(moment = "18:00:00")
@MinuteIn({ 0, 15, 30, 45 })
@HourNotIn(12)
@MinutePrecision
ZonedDateTime appointmentDateTime;
or alternatively:
@DayOfWeekIn({ MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY })
@HourIn({ 9, 10, 11, 13, 14, 15, 16, 17 })
@MinuteIn({ 0, 15, 30, 45 })
@MinutePrecision
ZonedDateTime appointmentDateTime;
Custom constraint annotations
Combining provided constraint annotations
The provided constraint annotations provide enough functionality for most cases. However, when several constraints are combined, like the last example, that may become unreadable. In cases like that it's easy to create a new constraint annotation and annotate that with the provided constraint annotations:
@Documented
// annotations required for constraint annotations; the target can be simplified
@Constraint(validatedBy = {})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
// date/time annotations
@DayOfWeekIn({ MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY })
@HourIn({ 9, 10, 11, 13, 14, 15, 16, 17 })
@MinuteIn({ 0, 15, 30, 45 })
@MinutePrecision
// don't report violations for the above annotations separately
@ReportAsSingleViolation
public @interface AppointmentSlot {
String message() default "must be a valid appointment slot";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
Custom validators
In case the provided constraint annotations cannot be combined to achieve the desired result, module date-time-base-validators
provides some base classes that can be used to write custom constraint validators. These all use functional interfaces to define custom behaviour; most of them can be supplied using method references. See package com.github.robtimus.validation.datetime.base for an overview.
Bean Validation API support
Version 2.x of this library has been written for Jakarta Bean Validation 3.0, as part of Jakarta EE 9.
Version 1.x of this library has been written for Jakarta Bean Validation 2.0, as part of Jakarta EE 8. However, it should also work with Bean Valdation 2.0 (non-Jakarta) and Bean Validation 1.1.