From 863248034b46c8292bf53681730fa033292710fa Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Fri, 17 Feb 2017 11:32:36 -0200 Subject: [PATCH] Support time.Time on form binding (#801) --- binding/form_mapping.go | 27 +++++++++++++++++++++++++++ context_test.go | 20 +++++++++++++++----- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/binding/form_mapping.go b/binding/form_mapping.go index 07c8375..bc9e44c 100644 --- a/binding/form_mapping.go +++ b/binding/form_mapping.go @@ -8,6 +8,7 @@ import ( "errors" "reflect" "strconv" + "time" ) func mapForm(ptr interface{}, form map[string][]string) error { @@ -52,6 +53,12 @@ func mapForm(ptr interface{}, form map[string][]string) error { } val.Field(i).Set(slice) } else { + if _, isTime := structField.Interface().(time.Time); isTime { + if err := setTimeField(inputValue[0], typeField, structField); err != nil { + return err + } + continue + } if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil { return err } @@ -140,6 +147,26 @@ func setFloatField(val string, bitSize int, field reflect.Value) error { return err } +func setTimeField(val string, structField reflect.StructField, value reflect.Value) error { + timeFormat := structField.Tag.Get("time_format") + if timeFormat == "" { + return errors.New("Blank time format") + } + + l := time.Local + if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC { + l = time.UTC + } + + t, err := time.ParseInLocation(timeFormat, val, l) + if err != nil { + return err + } + + value.Set(reflect.ValueOf(t)) + return nil +} + // Don't pass in pointers to bind to. Can lead to bugs. See: // https://github.com/codegangsta/martini-contrib/issues/40 // https://github.com/codegangsta/martini-contrib/pull/34#issuecomment-29683659 diff --git a/context_test.go b/context_test.go index 8d59f6e..ebc5050 100644 --- a/context_test.go +++ b/context_test.go @@ -42,6 +42,8 @@ func createMultipartRequest() *http.Request { must(mw.WriteField("array", "first")) must(mw.WriteField("array", "second")) must(mw.WriteField("id", "")) + must(mw.WriteField("time_local", "31/12/2016 14:55")) + must(mw.WriteField("time_utc", "31/12/2016 14:55")) req, err := http.NewRequest("POST", "/", body) must(err) req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary) @@ -309,11 +311,14 @@ func TestContextPostFormMultipart(t *testing.T) { c.Request = createMultipartRequest() var obj struct { - Foo string `form:"foo"` - Bar string `form:"bar"` - BarAsInt int `form:"bar"` - Array []string `form:"array"` - ID string `form:"id"` + Foo string `form:"foo"` + Bar string `form:"bar"` + BarAsInt int `form:"bar"` + Array []string `form:"array"` + ID string `form:"id"` + TimeLocal time.Time `form:"time_local" time_format:"02/01/2006 15:04"` + TimeUTC time.Time `form:"time_utc" time_format:"02/01/2006 15:04" time_utc:"1"` + BlankTime time.Time `form:"blank_time" time_format:"02/01/2006 15:04"` } assert.NoError(t, c.Bind(&obj)) assert.Equal(t, obj.Foo, "bar") @@ -321,6 +326,11 @@ func TestContextPostFormMultipart(t *testing.T) { assert.Equal(t, obj.BarAsInt, 10) assert.Equal(t, obj.Array, []string{"first", "second"}) assert.Equal(t, obj.ID, "") + assert.Equal(t, obj.TimeLocal.Format("02/01/2006 15:04"), "31/12/2016 14:55") + assert.Equal(t, obj.TimeLocal.Location(), time.Local) + assert.Equal(t, obj.TimeUTC.Format("02/01/2006 15:04"), "31/12/2016 14:55") + assert.Equal(t, obj.TimeUTC.Location(), time.UTC) + assert.True(t, obj.BlankTime.IsZero()) value, ok := c.GetQuery("foo") assert.False(t, ok)