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.offor 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.timepackage,momentmust be valid according to the class'parsemethod. - For
Date,momentmust be valid according toInstant.parse. - For
Calendar,momentmust be valid according toZonedDateTime.parse. durationmay not contain parts that are not present in the type. For instance, forLocalDatedurationmay not contain any time elements, forLocalTimeit may not contain any date elements, forYearMonthit 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.
