From c2d1fd86e50635ace935d3dbe198afd86e87ea8f Mon Sep 17 00:00:00 2001 From: Thomas Pelletier Date: Fri, 21 May 2021 09:37:43 -0400 Subject: [PATCH] Fix timezone detection when time has fractional component (#544) --- benchmark/benchmark_test.go | 17 +++++++++++++++++ decode.go | 8 ++++++++ parser.go | 4 ++-- unmarshaler_test.go | 20 +++++++++++++++++++- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/benchmark/benchmark_test.go b/benchmark/benchmark_test.go index 3e6c485..b495140 100644 --- a/benchmark/benchmark_test.go +++ b/benchmark/benchmark_test.go @@ -145,6 +145,23 @@ func BenchmarkReferenceFile(b *testing.B) { } } +func BenchmarkReferenceFileMap(b *testing.B) { + bytes, err := ioutil.ReadFile("benchmark.toml") + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(bytes))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m := map[string]interface{}{} + err := toml.Unmarshal(bytes, &m) + if err != nil { + panic(err) + } + } +} + func TestReferenceFile(t *testing.T) { bytes, err := ioutil.ReadFile("benchmark.toml") require.NoError(t, err) diff --git a/decode.go b/decode.go index 33ac2a9..88e6a42 100644 --- a/decode.go +++ b/decode.go @@ -172,6 +172,14 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) { digits := 0 for i, c := range b[minLengthWithFrac:] { + if !isDigit(c) { + if i == 0 { + return t, nil, newDecodeError(b[i:i+1], "need at least one digit after fraction point") + } + + break + } + const maxFracPrecision = 9 if i >= maxFracPrecision { return t, nil, newDecodeError(b[i:i+1], "maximum precision for date time is nanosecond") diff --git a/parser.go b/parser.go index eefbf03..b4caf73 100644 --- a/parser.go +++ b/parser.go @@ -823,8 +823,8 @@ byteLoop: switch { case isDigit(c): case c == '-': - const offsetOfTz = 19 - if i == offsetOfTz { + const minOffsetOfTz = 8 + if i >= minOffsetOfTz { hasTz = true } case c == 'T' || c == ':' || c == '.': diff --git a/unmarshaler_test.go b/unmarshaler_test.go index 6346b8e..d9203a6 100644 --- a/unmarshaler_test.go +++ b/unmarshaler_test.go @@ -268,6 +268,20 @@ func TestUnmarshal(t *testing.T) { } }, }, + { + desc: "time.time with zone and fractional", + input: `a = 1979-05-27T00:32:00.999999-07:00`, + gen: func() test { + var v map[string]time.Time + + return test{ + target: &v, + expected: &map[string]time.Time{ + "a": time.Date(1979, 5, 27, 0, 32, 0, 999999000, time.FixedZone("", -7*3600)), + }, + } + }, + }, { desc: "issue 475 - space between dots in key", input: `fruit. color = "yellow" @@ -1376,7 +1390,11 @@ func TestUnmarshalDecodeErrors(t *testing.T) { }, { desc: "wrong time offset separator", - data: `a = 1979-05-27T00:32:00T07:00`, + data: `a = 1979-05-27T00:32:00.-07:00`, + }, + { + desc: "missing fractional with tz", + data: `a = 2021-05-09T11:22:33.99999999999`, }, { desc: "wrong time offset separator",