diff --git a/src/time/format.go b/src/time/format.go index 87e990d48a4fa0..ad5486f4d28f89 100644 --- a/src/time/format.go +++ b/src/time/format.go @@ -1602,6 +1602,16 @@ func leadingFraction(s string) (x uint64, scale float64, rem string) { return x, scale, s[i:] } +// parseDurationError describes a problem parsing a duration string. +type parseDurationError struct { + message string + value string +} + +func (e *parseDurationError) Error() string { + return "time: " + e.message + " " + quote(e.value) +} + var unitMap = map[string]uint64{ "ns": uint64(Nanosecond), "us": uint64(Microsecond), @@ -1637,7 +1647,7 @@ func ParseDuration(s string) (Duration, error) { return 0, nil } if s == "" { - return 0, errors.New("time: invalid duration " + quote(orig)) + return 0, &parseDurationError{"invalid duration", orig} } for s != "" { var ( @@ -1649,13 +1659,13 @@ func ParseDuration(s string) (Duration, error) { // The next character must be [0-9.] if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') { - return 0, errors.New("time: invalid duration " + quote(orig)) + return 0, &parseDurationError{"invalid duration", orig} } // Consume [0-9]* pl := len(s) v, s, err = leadingInt(s) if err != nil { - return 0, errors.New("time: invalid duration " + quote(orig)) + return 0, &parseDurationError{"invalid duration", orig} } pre := pl != len(s) // whether we consumed anything before a period @@ -1669,7 +1679,7 @@ func ParseDuration(s string) (Duration, error) { } if !pre && !post { // no digits (e.g. ".s" or "-.s") - return 0, errors.New("time: invalid duration " + quote(orig)) + return 0, &parseDurationError{"invalid duration", orig} } // Consume unit. @@ -1681,17 +1691,17 @@ func ParseDuration(s string) (Duration, error) { } } if i == 0 { - return 0, errors.New("time: missing unit in duration " + quote(orig)) + return 0, &parseDurationError{"missing unit in duration", orig} } u := s[:i] s = s[i:] unit, ok := unitMap[u] if !ok { - return 0, errors.New("time: unknown unit " + quote(u) + " in duration " + quote(orig)) + return 0, &parseDurationError{"unknown unit " + quote(u) + " in duration", orig} } if v > 1<<63/unit { // overflow - return 0, errors.New("time: invalid duration " + quote(orig)) + return 0, &parseDurationError{"invalid duration", orig} } v *= unit if f > 0 { @@ -1700,19 +1710,19 @@ func ParseDuration(s string) (Duration, error) { v += uint64(float64(f) * (float64(unit) / scale)) if v > 1<<63 { // overflow - return 0, errors.New("time: invalid duration " + quote(orig)) + return 0, &parseDurationError{"invalid duration", orig} } } d += v if d > 1<<63 { - return 0, errors.New("time: invalid duration " + quote(orig)) + return 0, &parseDurationError{"invalid duration", orig} } } if neg { return -Duration(d), nil } if d > 1<<63-1 { - return 0, errors.New("time: invalid duration " + quote(orig)) + return 0, &parseDurationError{"invalid duration", orig} } return Duration(d), nil } diff --git a/src/time/time_test.go b/src/time/time_test.go index a2d4305c8c2084..a453ee043c4985 100644 --- a/src/time/time_test.go +++ b/src/time/time_test.go @@ -1620,6 +1620,13 @@ func BenchmarkParseDuration(b *testing.B) { } } +func BenchmarkParseDurationError(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseDuration("9223372036854775810ns") // overflow + ParseDuration("9007199254.740993") // missing unit + } +} + func BenchmarkHour(b *testing.B) { t := Now() for i := 0; i < b.N; i++ {