Time Rules
Learn how to validate time.Time fields in NLG Form using before, after, range, equality, zero-value, and custom validation rules.
Time rules validate typed time.Time fields defined with form.Time.
They are useful for validating dates, deadlines, booking windows, expiration times, scheduled jobs, event ranges, availability periods, and other time-based application data.
Common Use Cases
Time rules are commonly used for:
- booking dates
- appointment scheduling
- event start and end times
- token expiration dates
- subscription periods
- billing cycles
- deadline validation
- date range validation
- availability windows
- scheduled background jobs
TL;DR
| Rule | Description |
|---|---|
rules.After(field, t) | Requires the time value to be after t |
rules.AfterWithCode(field, t, code) | Same as After with a custom error code |
rules.Before(field, t) | Requires the time value to be before t |
rules.BeforeWithCode(field, t, code) | Same as Before with a custom error code |
rules.BetweenTime(field, min, max) | Requires the time value to be between min and max |
rules.BetweenTimeWithCode(field, min, max, code) | Same as BetweenTime with a custom error code |
rules.TimeEquals(field, expected) | Requires the time value to exactly match expected |
rules.TimeEqualsWithCode(field, expected, code) | Same as TimeEquals with a custom error code |
rules.NotZeroTime(field) | Requires the time value to be non-zero |
rules.NotZeroTimeWithCode(field, code) | Same as NotZeroTime with a custom error code |
rules.IsTime(field) | Validates that the field contains a time value |
Defining Time Fields
Time validation starts by defining typed time.Time fields.
TimeForm := struct {
StartAt form.TimeField[TimeRulesRequest]
EndAt form.TimeField[TimeRulesRequest]
ExpireAt form.TimeField[TimeRulesRequest]
}{
StartAt: form.Time[TimeRulesRequest]("start_at", func(r *TimeRulesRequest) time.Time {
return r.StartAt
}),
EndAt: form.Time[TimeRulesRequest]("end_at", func(r *TimeRulesRequest) time.Time {
return r.EndAt
}),
ExpireAt: form.Time[TimeRulesRequest]("expire_at", func(r *TimeRulesRequest) time.Time {
return r.ExpireAt
}),
}Each field contains:
- the validation response field name
- typed accessors
- reusable schema references
- strongly typed
time.Timeaccess
Applying Time Rules
Time rules are attached directly to typed field references.
return form.Schema[TimeRulesRequest]{
rules.NotZeroTime(TimeForm.StartAt),
rules.After(TimeForm.StartAt, time.Now()),
rules.Before(TimeForm.EndAt, time.Now().Add(30*24*time.Hour)),
}This keeps validation logic:
- explicit
- reusable
- composable
- transport-independent
- type-safe
Rule Examples
After
Requires the time value to be after the provided reference time.
rules.After(TimeForm.StartAt, time.Now())Typical use cases:
- future appointments
- booking start dates
- scheduled jobs
- expiration windows
AfterWithCode
Requires the time value to be after the reference time and returns a custom validation code.
const CodeMustBeFuture = form.Code("must_be_future")
rules.AfterWithCode(
TimeForm.StartAt,
time.Now(),
CodeMustBeFuture,
)Useful for frontend-friendly API validation responses.
Before
Requires the time value to be before the provided reference time.
rules.Before(TimeForm.EndAt, time.Now().Add(30*24*time.Hour))Typical use cases:
- maximum booking windows
- expiration limits
- trial periods
- scheduled release deadlines
BeforeWithCode
Requires the time value to be before the reference time and returns a custom validation code.
const CodeTooFarInFuture = form.Code("too_far_in_future")
rules.BeforeWithCode(
TimeForm.EndAt,
time.Now().Add(30*24*time.Hour),
CodeTooFarInFuture,
)BetweenTime
Requires the time value to be between the provided minimum and maximum time.
rules.BetweenTime(
TimeForm.StartAt,
time.Now(),
time.Now().Add(30*24*time.Hour),
)Typical use cases:
- valid booking windows
- subscription periods
- allowed scheduling ranges
- event availability windows
BetweenTimeWithCode
Requires the time value to stay within the provided time range and returns a custom validation code.
const CodeInvalidDateRange = form.Code("invalid_date_range")
rules.BetweenTimeWithCode(
TimeForm.StartAt,
time.Now(),
time.Now().Add(30*24*time.Hour),
CodeInvalidDateRange,
)TimeEquals
Requires the time value to exactly match the expected time.
rules.TimeEquals(TimeForm.StartAt, expectedStart)This is useful for strict workflows where a timestamp must match a known value.
TimeEqualsWithCode
Requires the time value to exactly match the expected time and returns a custom validation code.
const CodeInvalidTimestamp = form.Code("invalid_timestamp")
rules.TimeEqualsWithCode(
TimeForm.StartAt,
expectedStart,
CodeInvalidTimestamp,
)NotZeroTime
Requires the time value to be non-zero.
rules.NotZeroTime(TimeForm.StartAt)Typical use cases:
- required date fields
- required scheduling input
- required expiration values
NotZeroTimeWithCode
Requires the time value to be non-zero and returns a custom validation code.
const CodeDateRequired = form.Code("date_required")
rules.NotZeroTimeWithCode(
TimeForm.StartAt,
CodeDateRequired,
)IsTime
Checks whether the field contains a valid time value.
rules.IsTime(TimeForm.StartAt)For typed Go structures this rule is mostly useful for API symmetry because invalid JSON time values are usually rejected during request decoding before schema validation begins.
Complete Example
package main
import (
"time"
"github.com/netlifeguru/form"
"github.com/netlifeguru/form/rules"
)
type TimeRulesRequest struct {
StartAt time.Time `json:"start_at"`
EndAt time.Time `json:"end_at"`
ExpireAt time.Time `json:"expire_at"`
}
func TimeRulesSchema() form.Schema[TimeRulesRequest] {
now := time.Now()
max := now.Add(30 * 24 * time.Hour)
TimeForm := struct {
StartAt form.TimeField[TimeRulesRequest]
EndAt form.TimeField[TimeRulesRequest]
ExpireAt form.TimeField[TimeRulesRequest]
}{
StartAt: form.Time[TimeRulesRequest]("start_at", func(r *TimeRulesRequest) time.Time {
return r.StartAt
}),
EndAt: form.Time[TimeRulesRequest]("end_at", func(r *TimeRulesRequest) time.Time {
return r.EndAt
}),
ExpireAt: form.Time[TimeRulesRequest]("expire_at", func(r *TimeRulesRequest) time.Time {
return r.ExpireAt
}),
}
return form.Schema[TimeRulesRequest]{
rules.NotZeroTime(TimeForm.StartAt),
rules.After(TimeForm.StartAt, now),
rules.Before(TimeForm.EndAt, max),
rules.BetweenTime(TimeForm.ExpireAt, now, max),
}
}Notes
- Time rules operate on typed Go
time.Timevalues. - Invalid JSON time formats are rejected during request decoding before validation begins.
- Use
NotZeroTimefor required date or timestamp fields. - Use
After,Before, andBetweenTimefor scheduling, booking, and expiration workflows. - Time comparison uses Go’s standard
time.Timecomparison methods. - Be careful when using
time.Now()directly in schemas if the schema is cached globally. Prefer schema functions when validation depends on the current time. - Custom error codes help stabilize frontend-facing validation contracts.
- Time validation remains explicit and independent from HTTP, JSON, CLI, or background worker transport layers.
String Rules
Learn how to validate string fields in NLG Form using required checks, length validation, prefixes, suffixes, substrings, equality rules, and custom validation codes.
Required Rules
Learn how required validation works in NLG Form, how empty values are handled, and why required rules change validation behavior for optional and zero-value fields.