diff --git a/schema/time.go b/schema/time.go index 5c54ea7e..34adeb27 100644 --- a/schema/time.go +++ b/schema/time.go @@ -52,12 +52,28 @@ var ( // Time validates time based values type Time struct { + TimeLayouts []string // TimeLayouts is set of time layouts we want to validate + layouts []string +} + +// Compile the time formats +func (v *Time) Compile() (err error) { + if len(v.TimeLayouts) == 0 { + // default layouts to all formats + v.layouts = formats + return nil + } + // User specified list of time layouts + for _, layout := range v.TimeLayouts { + v.layouts = append(v.layouts, string(layout)) + } + return nil } // Validate validates and normalize time based value func (v Time) Validate(value interface{}) (interface{}, error) { if s, ok := value.(string); ok { - for _, layout := range formats { + for _, layout := range v.layouts { if t, err := time.Parse(layout, s); err == nil { value = t break diff --git a/schema/time_test.go b/schema/time_test.go index 1fb40367..a304bb63 100644 --- a/schema/time_test.go +++ b/schema/time_test.go @@ -9,17 +9,50 @@ import ( func TestTimeValidate(t *testing.T) { now := time.Now().Truncate(time.Minute).UTC() + timeT := Time{} + err := timeT.Compile() + assert.NoError(t, err) for _, f := range formats { - v, err := Time{}.Validate(now.Format(f)) + v, err := timeT.Validate(now.Format(f)) assert.NoError(t, err) if assert.IsType(t, v, now) { assert.True(t, now.Equal(v.(time.Time)), f) } } - v, err := Time{}.Validate(now) + v, err := timeT.Validate(now) assert.NoError(t, err) assert.Equal(t, now, v) - v, err = Time{}.Validate("invalid date") + v, err = timeT.Validate("invalid date") assert.EqualError(t, err, "not a time") assert.Nil(t, v) } + +func TestTimeSpecificLayoutList(t *testing.T) { + now := time.Now().Truncate(time.Minute).UTC() + // list to test for + testList := []string{time.RFC1123Z, time.RFC822Z, time.RFC3339} + // test for same list in reverse + timeT := Time{TimeLayouts: []string{time.RFC3339, time.RFC822Z, time.RFC1123Z}} + err := timeT.Compile() + assert.NoError(t, err) + // expect no errors + for _, f := range testList { + _, err := timeT.Validate(now.Format(f)) + assert.NoError(t, err) + } +} + +func TestTimeForTimeLayoutFailure(t *testing.T) { + now := time.Now().Truncate(time.Minute).UTC() + // test for ANSIC time + testList := []string{time.ANSIC} + // configure for RFC3339 time + timeT := Time{TimeLayouts: []string{time.RFC3339}} + err := timeT.Compile() + assert.NoError(t, err) + // expect an error + for _, f := range testList { + _, err := timeT.Validate(now.Format(f)) + assert.EqualError(t, err, "not a time") + } +}