diff --git a/src/time/export_test.go b/src/time/export_test.go index f4a8cd9b72a..0f2d21053a3 100644 --- a/src/time/export_test.go +++ b/src/time/export_test.go @@ -51,6 +51,7 @@ const ( RuleJulian = RuleKind(ruleJulian) RuleDOY = RuleKind(ruleDOY) RuleMonthWeekDay = RuleKind(ruleMonthWeekDay) + UnixToInternal = unixToInternal ) type Rule struct { diff --git a/src/time/internal_test.go b/src/time/internal_test.go index ffe54e47c2d..87a4208b058 100644 --- a/src/time/internal_test.go +++ b/src/time/internal_test.go @@ -62,4 +62,6 @@ func CheckRuntimeTimerPeriodOverflow() { var ( MinMonoTime = Time{wall: 1 << 63, ext: -1 << 63, loc: UTC} MaxMonoTime = Time{wall: 1 << 63, ext: 1<<63 - 1, loc: UTC} + + NotMonoNegativeTime = Time{wall: 0, ext: -1<<63 + 50} ) diff --git a/src/time/time.go b/src/time/time.go index 7e5192a0c97..841f989293c 100644 --- a/src/time/time.go +++ b/src/time/time.go @@ -189,8 +189,15 @@ func (t *Time) addSec(d int64) { t.stripMono() } - // TODO: Check for overflow. - t.ext += d + // Check if the sum of t.ext and d overflows and handle it properly. + sum := t.ext + d + if (sum > t.ext) == (d > 0) { + t.ext = sum + } else if d > 0 { + t.ext = 1<<63 - 1 + } else { + t.ext = -(1<<63 - 1) + } } // setLoc sets the location associated with the time. diff --git a/src/time/time_test.go b/src/time/time_test.go index 8884731e1d0..3a58bfe4e94 100644 --- a/src/time/time_test.go +++ b/src/time/time_test.go @@ -1481,7 +1481,7 @@ func TestTimeIsDST(t *testing.T) { tzFixed := FixedZone("FIXED_TIME", 12345) tests := [...]struct { - time Time + time Time want bool }{ 0: {Date(2009, 1, 1, 12, 0, 0, 0, UTC), false}, @@ -1501,3 +1501,28 @@ func TestTimeIsDST(t *testing.T) { } } } + +func TestTimeAddSecOverflow(t *testing.T) { + // Test it with positive delta. + var maxInt64 int64 = 1<<63 - 1 + timeExt := maxInt64 - UnixToInternal - 50 + notMonoTime := Unix(timeExt, 0) + for i := int64(0); i < 100; i++ { + sec := notMonoTime.Unix() + notMonoTime = notMonoTime.Add(Duration(i * 1e9)) + if newSec := notMonoTime.Unix(); newSec != sec+i && newSec+UnixToInternal != maxInt64 { + t.Fatalf("time ext: %d overflows with positive delta, overflow threshold: %d", newSec, maxInt64) + } + } + + // Test it with negative delta. + maxInt64 = -maxInt64 + notMonoTime = NotMonoNegativeTime + for i := int64(0); i > -100; i-- { + sec := notMonoTime.Unix() + notMonoTime = notMonoTime.Add(Duration(i * 1e9)) + if newSec := notMonoTime.Unix(); newSec != sec+i && newSec+UnixToInternal != maxInt64 { + t.Fatalf("time ext: %d overflows with positive delta, overflow threshold: %d", newSec, maxInt64) + } + } +}