Skip to content

Commit 44f3347

Browse files
committed
Add support for time zone validation
1 parent ea924ce commit 44f3347

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

baked_in.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ var (
174174
"lowercase": isLowercase,
175175
"uppercase": isUppercase,
176176
"datetime": isDatetime,
177+
"timeZone": isTimeZone,
177178
}
178179
)
179180

@@ -2096,3 +2097,29 @@ func isDatetime(fl FieldLevel) bool {
20962097

20972098
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
20982099
}
2100+
2101+
// isTimeZone is the validation function for validating if the current field's value is a valid time zone string.
2102+
func isTimeZone(fl FieldLevel) bool {
2103+
field := fl.Field()
2104+
2105+
if field.Kind() == reflect.String {
2106+
// empty value is converted to UTC by time.LoadLocation but disallow it as it is not a valid time zone name
2107+
if field.String() == "" {
2108+
return false
2109+
}
2110+
2111+
// Local value is converted to the current system time zone by time.LoadLocation but disallow it as it is not a valid time zone name
2112+
if strings.ToLower(field.String()) == "local" {
2113+
return false
2114+
}
2115+
2116+
_, err := time.LoadLocation(field.String())
2117+
if err != nil {
2118+
return false
2119+
}
2120+
2121+
return true
2122+
}
2123+
2124+
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2125+
}

doc.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,14 @@ Supplied format must match the official Go time format layout as documented in h
10881088
10891089
Usage: datetime=2006-01-02
10901090
1091+
TimeZone
1092+
1093+
This validates that a string value is a valid time zone based on the time zone database present on the system.
1094+
Although empty value and Local value are allowed by time.LoadLocation golang function, they are not allowed by this validator.
1095+
More information on https://golang.org/pkg/time/#LoadLocation
1096+
1097+
Usage: timeZone
1098+
10911099
Alias Validators and Tags
10921100
10931101
NOTE: When returning an error, the tag returned in "FieldError" will be

validator_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9201,3 +9201,44 @@ func TestDatetimeValidation(t *testing.T) {
92019201
_ = validate.Var(2, "datetime")
92029202
}, "Bad field type int")
92039203
}
9204+
9205+
func TestTimeZoneValidation(t *testing.T) {
9206+
tests := []struct {
9207+
value string `validate:"timeZone"`
9208+
tag string
9209+
expected bool
9210+
}{
9211+
// systems may have different time zone database, some systems time zone are case insensitive
9212+
{"America/New_York", `timeZone`, true},
9213+
{"UTC", `timeZone`, true},
9214+
{"", `timeZone`, false},
9215+
{"Local", `timeZone`, false},
9216+
{"Unknown", `timeZone`, false},
9217+
}
9218+
9219+
validate := New()
9220+
9221+
for i, test := range tests {
9222+
9223+
errs := validate.Var(test.value, test.tag)
9224+
9225+
if test.expected {
9226+
if !IsEqual(errs, nil) {
9227+
t.Fatalf("Index: %d time zone failed Error: %s", i, errs)
9228+
}
9229+
} else {
9230+
if IsEqual(errs, nil) {
9231+
t.Fatalf("Index: %d time zone failed Error: %s", i, errs)
9232+
} else {
9233+
val := getError(errs, "", "")
9234+
if val.Tag() != "timeZone" {
9235+
t.Fatalf("Index: %d time zone failed Error: %s", i, errs)
9236+
}
9237+
}
9238+
}
9239+
}
9240+
9241+
PanicMatches(t, func() {
9242+
_ = validate.Var(2, "timeZone")
9243+
}, "Bad field type int")
9244+
}

0 commit comments

Comments
 (0)