diff --git a/src/time/format.go b/src/time/format.go index 7373892b97..464effdb43 100644 --- a/src/time/format.go +++ b/src/time/format.go @@ -1420,16 +1420,19 @@ func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, err = errBad return } + if nbytes > 10 { + value = value[:10] + nbytes = 10 + } if ns, err = atoi(value[1:nbytes]); err != nil { return } - if ns < 0 || 1e9 <= ns { + if ns < 0 { rangeErrString = "fractional second" return } // We need nanoseconds, which means scaling by the number - // of missing digits in the format, maximum length 10. If it's - // longer than 10, we won't scale. + // of missing digits in the format, maximum length 10. scaleDigits := 10 - nbytes for i := 0; i < scaleDigits; i++ { ns *= 10 diff --git a/src/time/format_test.go b/src/time/format_test.go index 93cbcf9401..db95536390 100644 --- a/src/time/format_test.go +++ b/src/time/format_test.go @@ -852,3 +852,44 @@ func TestFormatFractionalSecondSeparators(t *testing.T) { } } } + +// Issue 48685 +func TestParseFractionalSecondsLongerThanNineDigits(t *testing.T) { + tests := []struct { + s string + want int + }{ + // 9 digits + {"2021-09-29T16:04:33.000000000Z", 0}, + {"2021-09-29T16:04:33.000000001Z", 1}, + {"2021-09-29T16:04:33.100000000Z", 100_000_000}, + {"2021-09-29T16:04:33.100000001Z", 100_000_001}, + {"2021-09-29T16:04:33.999999999Z", 999_999_999}, + {"2021-09-29T16:04:33.012345678Z", 12_345_678}, + // 10 digits, truncates + {"2021-09-29T16:04:33.0000000000Z", 0}, + {"2021-09-29T16:04:33.0000000001Z", 0}, + {"2021-09-29T16:04:33.1000000000Z", 100_000_000}, + {"2021-09-29T16:04:33.1000000009Z", 100_000_000}, + {"2021-09-29T16:04:33.9999999999Z", 999_999_999}, + {"2021-09-29T16:04:33.0123456789Z", 12_345_678}, + // 11 digits, truncates + {"2021-09-29T16:04:33.10000000000Z", 100_000_000}, + {"2021-09-29T16:04:33.00123456789Z", 1_234_567}, + // 12 digits, truncates + {"2021-09-29T16:04:33.000123456789Z", 123_456}, + // 15 digits, truncates + {"2021-09-29T16:04:33.9999999999999999Z", 999_999_999}, + } + + for _, tt := range tests { + tm, err := Parse(RFC3339, tt.s) + if err != nil { + t.Errorf("Unexpected error: %v", err) + continue + } + if got := tm.Nanosecond(); got != tt.want { + t.Errorf("Parse(%q) = got %d, want %d", tt.s, got, tt.want) + } + } +}