diff options
Diffstat (limited to 'libgo/go/time/format.go')
-rw-r--r-- | libgo/go/time/format.go | 150 |
1 files changed, 130 insertions, 20 deletions
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go index 082a51a1621..bd02b486720 100644 --- a/libgo/go/time/format.go +++ b/libgo/go/time/format.go @@ -283,25 +283,16 @@ var atoiError = errors.New("time: invalid number") // Duplicates functionality in strconv, but avoids dependency. func atoi(s string) (x int, err error) { - i := 0 - if len(s) > 0 && s[0] == '-' { - i++ + neg := false + if s != "" && s[0] == '-' { + neg = true + s = s[1:] } - if i >= len(s) { + x, rem, err := leadingInt(s) + if err != nil || rem != "" { return 0, atoiError } - for ; i < len(s); i++ { - c := s[i] - if c < '0' || c > '9' { - return 0, atoiError - } - if x >= (1<<31-10)/10 { - // will overflow - return 0, atoiError - } - x = x*10 + int(c) - '0' - } - if s[0] == '-' { + if neg { x = -x } return x, nil @@ -344,10 +335,6 @@ func (b *buffer) WriteString(s string) { *b = append(*b, s...) } -func (b *buffer) WriteByte(c byte) { - *b = append(*b, c) -} - func (b *buffer) String() string { return string([]byte(*b)) } @@ -893,3 +880,126 @@ func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, } return } + +var errLeadingInt = errors.New("time: bad [0-9]*") // never printed + +// leadingInt consumes the leading [0-9]* from s. +func leadingInt(s string) (x int, rem string, err error) { + i := 0 + for ; i < len(s); i++ { + c := s[i] + if c < '0' || c > '9' { + break + } + if x >= (1<<31-10)/10 { + // overflow + return 0, "", errLeadingInt + } + x = x*10 + int(c) - '0' + } + return x, s[i:], nil +} + +var unitMap = map[string]float64{ + "ns": float64(Nanosecond), + "us": float64(Microsecond), + "µs": float64(Microsecond), // U+00B5 = micro symbol + "μs": float64(Microsecond), // U+03BC = Greek letter mu + "ms": float64(Millisecond), + "s": float64(Second), + "m": float64(Minute), + "h": float64(Hour), +} + +// ParseDuration parses a duration string. +// A duration string is a possibly signed sequence of +// decimal numbers, each with optional fraction and a unit suffix, +// such as "300ms", "-1.5h" or "2h45m". +// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". +func ParseDuration(s string) (Duration, error) { + // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+ + orig := s + f := float64(0) + neg := false + + // Consume [-+]? + if s != "" { + c := s[0] + if c == '-' || c == '+' { + neg = c == '-' + s = s[1:] + } + } + // Special case: if all that is left is "0", this is zero. + if s == "0" { + return 0, nil + } + if s == "" { + return 0, errors.New("time: invalid duration " + orig) + } + for s != "" { + g := float64(0) // this element of the sequence + + var x int + var err error + + // The next character must be [0-9.] + if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) { + return 0, errors.New("time: invalid duration " + orig) + } + // Consume [0-9]* + pl := len(s) + x, s, err = leadingInt(s) + if err != nil { + return 0, errors.New("time: invalid duration " + orig) + } + g = float64(x) + pre := pl != len(s) // whether we consumed anything before a period + + // Consume (\.[0-9]*)? + post := false + if s != "" && s[0] == '.' { + s = s[1:] + pl := len(s) + x, s, err = leadingInt(s) + if err != nil { + return 0, errors.New("time: invalid duration " + orig) + } + scale := 1 + for n := pl - len(s); n > 0; n-- { + scale *= 10 + } + g += float64(x) / float64(scale) + post = pl != len(s) + } + if !pre && !post { + // no digits (e.g. ".s" or "-.s") + return 0, errors.New("time: invalid duration " + orig) + } + + // Consume unit. + i := 0 + for ; i < len(s); i++ { + c := s[i] + if c == '.' || ('0' <= c && c <= '9') { + break + } + } + if i == 0 { + return 0, errors.New("time: missing unit in duration " + orig) + } + u := s[:i] + s = s[i:] + unit, ok := unitMap[u] + if !ok { + return 0, errors.New("time: unknown unit " + u + " in duration " + orig) + } + + f += g * unit + } + + if neg { + f = -f + } + return Duration(f), nil +} |