From b4f3c9339e77e70cbd5b81ef7f2a4dec557d40de Mon Sep 17 00:00:00 2001 From: Simon Rawet Date: Sat, 28 May 2016 16:46:45 +0200 Subject: [PATCH] time: fix AddDate with nil location AddDate now retrieves location from t.Location() to ensure that it never calls Date with a nil location. Added test for this bug on all Time's methods Fixes #15852 Change-Id: Id2a222af56993f741ad0b802a2c3b89e8e463926 Reviewed-on: https://go-review.googlesource.com/23561 Reviewed-by: Russ Cox Run-TryBot: Russ Cox --- src/time/time.go | 2 +- src/time/time_test.go | 92 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/src/time/time.go b/src/time/time.go index d3a9d1b3cd..8f16986044 100644 --- a/src/time/time.go +++ b/src/time/time.go @@ -657,7 +657,7 @@ func Until(t Time) Duration { func (t Time) AddDate(years int, months int, days int) Time { year, month, day := t.Date() hour, min, sec := t.Clock() - return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec), t.loc) + return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec), t.Location()) } const ( diff --git a/src/time/time_test.go b/src/time/time_test.go index 2e47d0819d..293c71203a 100644 --- a/src/time/time_test.go +++ b/src/time/time_test.go @@ -1039,6 +1039,98 @@ func TestDurationHours(t *testing.T) { } } +var defaultLocTests = []struct { + name string + f func(t1, t2 Time) bool +}{ + {"After", func(t1, t2 Time) bool { return t1.After(t2) == t2.After(t1) }}, + {"Before", func(t1, t2 Time) bool { return t1.Before(t2) == t2.Before(t1) }}, + {"Equal", func(t1, t2 Time) bool { return t1.Equal(t2) == t2.Equal(t1) }}, + + {"IsZero", func(t1, t2 Time) bool { return t1.IsZero() == t2.IsZero() }}, + {"Date", func(t1, t2 Time) bool { + a1, b1, c1 := t1.Date() + a2, b2, c2 := t2.Date() + return a1 == a2 && b1 == b2 && c1 == c2 + }}, + {"Year", func(t1, t2 Time) bool { return t1.Year() == t2.Year() }}, + {"Month", func(t1, t2 Time) bool { return t1.Month() == t2.Month() }}, + {"Day", func(t1, t2 Time) bool { return t1.Day() == t2.Day() }}, + {"Weekday", func(t1, t2 Time) bool { return t1.Weekday() == t2.Weekday() }}, + {"ISOWeek", func(t1, t2 Time) bool { + a1, b1 := t1.ISOWeek() + a2, b2 := t2.ISOWeek() + return a1 == a2 && b1 == b2 + }}, + {"Clock", func(t1, t2 Time) bool { + a1, b1, c1 := t1.Clock() + a2, b2, c2 := t2.Clock() + return a1 == a2 && b1 == b2 && c1 == c2 + }}, + {"Hour", func(t1, t2 Time) bool { return t1.Hour() == t2.Hour() }}, + {"Minute", func(t1, t2 Time) bool { return t1.Minute() == t2.Minute() }}, + {"Second", func(t1, t2 Time) bool { return t1.Second() == t2.Second() }}, + {"Nanosecond", func(t1, t2 Time) bool { return t1.Hour() == t2.Hour() }}, + {"YearDay", func(t1, t2 Time) bool { return t1.YearDay() == t2.YearDay() }}, + + // Using Equal since Add don't modify loc using "==" will cause a fail + {"Add", func(t1, t2 Time) bool { return t1.Add(Hour).Equal(t2.Add(Hour)) }}, + {"Sub", func(t1, t2 Time) bool { return t1.Sub(t2) == t2.Sub(t1) }}, + + //Original caus for this test case bug 15852 + {"AddDate", func(t1, t2 Time) bool { return t1.AddDate(1991, 9, 3) == t2.AddDate(1991, 9, 3) }}, + + {"UTC", func(t1, t2 Time) bool { return t1.UTC() == t2.UTC() }}, + {"Local", func(t1, t2 Time) bool { return t1.Local() == t2.Local() }}, + {"In", func(t1, t2 Time) bool { return t1.In(UTC) == t2.In(UTC) }}, + + {"Local", func(t1, t2 Time) bool { return t1.Local() == t2.Local() }}, + {"Zone", func(t1, t2 Time) bool { + a1, b1 := t1.Zone() + a2, b2 := t2.Zone() + return a1 == a2 && b1 == b2 + }}, + + {"Unix", func(t1, t2 Time) bool { return t1.Unix() == t2.Unix() }}, + {"UnixNano", func(t1, t2 Time) bool { return t1.UnixNano() == t2.UnixNano() }}, + + {"MarshalBinary", func(t1, t2 Time) bool { + a1, b1 := t1.MarshalBinary() + a2, b2 := t2.MarshalBinary() + return bytes.Equal(a1, a2) && b1 == b2 + }}, + {"GobEncode", func(t1, t2 Time) bool { + a1, b1 := t1.GobEncode() + a2, b2 := t2.GobEncode() + return bytes.Equal(a1, a2) && b1 == b2 + }}, + {"MarshalJSON", func(t1, t2 Time) bool { + a1, b1 := t1.MarshalJSON() + a2, b2 := t2.MarshalJSON() + return bytes.Equal(a1, a2) && b1 == b2 + }}, + {"MarshalText", func(t1, t2 Time) bool { + a1, b1 := t1.MarshalText() + a2, b2 := t2.MarshalText() + return bytes.Equal(a1, a2) && b1 == b2 + }}, + + {"Truncate", func(t1, t2 Time) bool { return t1.Truncate(Hour).Equal(t2.Truncate(Hour)) }}, + {"Round", func(t1, t2 Time) bool { return t1.Round(Hour).Equal(t2.Round(Hour)) }}, +} + +func TestDefaultLoc(t *testing.T) { + //This test verifyes that all Time's methods behaves identical if loc is set + //as nil or UTC + for _, tt := range defaultLocTests { + t1 := Time{} + t2 := Time{}.UTC() + if !tt.f(t1, t2) { + t.Errorf("Default fail on fuction: %s", tt.name) + } + } +} + func BenchmarkNow(b *testing.B) { for i := 0; i < b.N; i++ { t = Now()