diff --git a/hashstructure.go b/hashstructure.go index ea13a15..1a15843 100644 --- a/hashstructure.go +++ b/hashstructure.go @@ -6,6 +6,7 @@ import ( "hash" "hash/fnv" "reflect" + "time" ) // ErrNotStringer is returned when there's an error with hash:"string" @@ -104,6 +105,8 @@ type visitOpts struct { StructField string } +var timeType = reflect.TypeOf(time.Time{}) + func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) { t := reflect.TypeOf(0) @@ -159,6 +162,18 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) { return w.h.Sum64(), err } + switch v.Type() { + case timeType: + w.h.Reset() + b, err := v.Interface().(time.Time).MarshalBinary() + if err != nil { + return 0, err + } + + err = binary.Write(w.h, binary.LittleEndian, b) + return w.h.Sum64(), err + } + switch k { case reflect.Array: var h uint64 diff --git a/hashstructure_test.go b/hashstructure_test.go index 13ab834..3d42deb 100644 --- a/hashstructure_test.go +++ b/hashstructure_test.go @@ -66,6 +66,8 @@ func TestHash_equal(t *testing.T) { type testFoo struct{ Name string } type testBar struct{ Name string } + now := time.Now() + cases := []struct { One, Two interface{} Match bool @@ -155,6 +157,12 @@ func TestHash_equal(t *testing.T) { }, true, }, + { + now, // contains monotonic clock + time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), + now.Minute(), now.Second(), now.Nanosecond(), now.Location()), // does not contain monotonic clock + true, + }, } for i, tc := range cases { @@ -247,6 +255,13 @@ func TestHash_equalIgnore(t *testing.T) { { TestTime2{Name: "foo", Time: now}, TestTime2{Name: "foo", Time: time.Time{}}, + false, + }, + { + TestTime2{Name: "foo", Time: now}, + TestTime2{Name: "foo", Time: time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), + now.Minute(), now.Second(), now.Nanosecond(), now.Location()), + }, true, }, }