diff --git a/model/time.go b/model/time.go index 1730b0fd..d053ada7 100644 --- a/model/time.go +++ b/model/time.go @@ -123,44 +123,38 @@ func (t Time) MarshalJSON() ([]byte, error) { // UnmarshalJSON implements the json.Unmarshaler interface. func (t *Time) UnmarshalJSON(b []byte) error { - p := strings.Split(string(b), ".") - switch len(p) { - case 1: - v, err := strconv.ParseInt(p[0], 10, 64) + base, frac, found := strings.Cut(string(b), ".") + if !found { + v, err := strconv.ParseInt(base, 10, 64) if err != nil { return err } *t = Time(v * second) - - case 2: - v, err := strconv.ParseInt(p[0], 10, 64) + } else { + v, err := strconv.ParseInt(base, 10, 64) if err != nil { return err } - v *= second - prec := dotPrecision - len(p[1]) + prec := dotPrecision - len(frac) if prec < 0 { - p[1] = p[1][:dotPrecision] - } else if prec > 0 { - p[1] += strings.Repeat("0", prec) + frac = frac[:dotPrecision] } - - va, err := strconv.ParseInt(p[1], 10, 32) + va, err := strconv.ParseInt(frac, 10, 32) if err != nil { return err } - - // If the value was something like -0.1 the negative is lost in the - // parsing because of the leading zero, this ensures that we capture it. - if len(p[0]) > 0 && p[0][0] == '-' && v+va > 0 { - *t = Time(v+va) * -1 - } else { - *t = Time(v + va) + switch prec { + case 1: + va *= 10 + case 2: + va *= 100 } - default: - return fmt.Errorf("invalid time %q", string(b)) + if len(base) > 0 && base[0] == '-' { + va = -va + } + *t = Time(v*second + va) } return nil } diff --git a/model/time_test.go b/model/time_test.go index a4e9069f..7633b46e 100644 --- a/model/time_test.go +++ b/model/time_test.go @@ -432,6 +432,11 @@ func TestTimeJSON(t *testing.T) { }{ {Time(1), `0.001`}, {Time(-1), `-0.001`}, + {Time(1001), `1.001`}, + {Time(-1001), `-1.001`}, + {Time(123000), `123`}, + {Time(123100), `123.1`}, + {Time(123010), `123.01`}, } for i, test := range tests { @@ -460,3 +465,17 @@ func BenchmarkParseDuration(b *testing.B) { require.NoError(b, err) } } + +func BenchmarkUnmarshalTime(b *testing.B) { + cases := []string{"1780924784", "1780924784.01", "1780924784.001"} + + for _, c := range cases { + b.Run(c, func(b *testing.B) { + var t Time + data := []byte(c) + for b.Loop() { + _ = t.UnmarshalJSON(data) + } + }) + } +}