Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions src/time/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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 (
Expand All @@ -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

Expand All @@ -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.
Expand All @@ -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 {
Expand All @@ -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
}
7 changes: 7 additions & 0 deletions src/time/time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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++ {
Expand Down