|
|
|
|
@ -9,6 +9,51 @@ import ( |
|
|
|
|
"time" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func TestParse3339(t *testing.T) { |
|
|
|
|
tests := []string{ |
|
|
|
|
"2020-04-05T15:56:00Z", |
|
|
|
|
"2020-04-05T15:56:00.1234Z", |
|
|
|
|
"2020-04-05T15:56:00+08:00", |
|
|
|
|
|
|
|
|
|
"2020-04-05T15:56:00.1+08:00", |
|
|
|
|
"2020-04-05T15:56:00.12+08:00", |
|
|
|
|
"2020-04-05T15:56:00.012+08:00", |
|
|
|
|
"2020-04-05T15:56:00.0012+08:00", |
|
|
|
|
"2020-04-05T15:56:00.148487491+08:00", |
|
|
|
|
|
|
|
|
|
"2020x04-05T15:56:00.1234+08:00", |
|
|
|
|
"2020-04x05T15:56:00.1234+08:00", |
|
|
|
|
"2020-04-05x15:56:00.1234+08:00", |
|
|
|
|
"2020-04-05T15x56:00.1234+08:00", |
|
|
|
|
"2020-04-05T15:56x00.1234+08:00", |
|
|
|
|
"2020-04-05T15:56:00x1234+08:00", |
|
|
|
|
} |
|
|
|
|
for _, s := range tests { |
|
|
|
|
t.Run(s, func(t *testing.T) { |
|
|
|
|
goTime, goErr := time.Parse(time.RFC3339Nano, s) |
|
|
|
|
|
|
|
|
|
Parse3339(s) // prime the tz cache so next parse use fast path
|
|
|
|
|
got, err := Parse3339(s) |
|
|
|
|
|
|
|
|
|
if (err == nil) != (goErr == nil) { |
|
|
|
|
t.Errorf("for %q, go err = %v; our err = %v", s, goErr, err) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
if err != nil { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
if !goTime.Equal(got) { |
|
|
|
|
t.Errorf("for %q, times not Equal: we got %v, want go's %v", s, got, goTime) |
|
|
|
|
} |
|
|
|
|
if goStr, ourStr := goTime.Format(time.RFC3339Nano), got.Format(time.RFC3339Nano); goStr != ourStr { |
|
|
|
|
t.Errorf("for %q, strings not equal: we got %q, want go's %q", s, ourStr, goStr) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func TestZoneOf(t *testing.T) { |
|
|
|
|
tests := []struct { |
|
|
|
|
in, want string |
|
|
|
|
@ -16,17 +61,14 @@ func TestZoneOf(t *testing.T) { |
|
|
|
|
{"2020-04-05T15:56:00+08:00", "+08:00"}, |
|
|
|
|
{"2020-04-05T15:56:00-08:00", "-08:00"}, |
|
|
|
|
{"2020-04-05T15:56:00.12345-08:00", "-08:00"}, |
|
|
|
|
// don't cache weird offsets, only 00 15, 30:
|
|
|
|
|
{"2020-04-05T15:56:00.12345-08:00", "-08:00"}, |
|
|
|
|
{"2020-04-05T15:56:00.12345-08:30", "-08:30"}, |
|
|
|
|
{"2020-04-05T15:56:00.12345-08:15", "-08:15"}, |
|
|
|
|
{"2020-04-05T15:56:00.12345-08:17", ""}, |
|
|
|
|
// don't cache UTC:
|
|
|
|
|
{"2020-04-05T15:56:00.12345Z", ""}, |
|
|
|
|
{"2020-04-05T15:56:00Z", ""}, |
|
|
|
|
// too short:
|
|
|
|
|
{"123+08:00", ""}, |
|
|
|
|
{"+08:00", ""}, |
|
|
|
|
{"2020-04-05T15:56:00.12345-08:17", ""}, // don't cache weird offsets
|
|
|
|
|
{"2020-04-05T15:56:00.12345Z", "Z"}, |
|
|
|
|
{"2020-04-05T15:56:00Z", "Z"}, |
|
|
|
|
{"123+08:00", ""}, // too short
|
|
|
|
|
{"+08:00", ""}, // too short
|
|
|
|
|
} |
|
|
|
|
for _, tt := range tests { |
|
|
|
|
if got := zoneOf(tt.in); got != tt.want { |
|
|
|
|
@ -36,14 +78,19 @@ func TestZoneOf(t *testing.T) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func BenchmarkGoParse3339(b *testing.B) { |
|
|
|
|
b.ReportAllocs() |
|
|
|
|
const in = `2020-04-05T15:56:00.148487491+08:00` |
|
|
|
|
for i := 0; i < b.N; i++ { |
|
|
|
|
_, err := time.Parse(time.RFC3339Nano, in) |
|
|
|
|
if err != nil { |
|
|
|
|
b.Fatal(err) |
|
|
|
|
run := func(in string) func(*testing.B) { |
|
|
|
|
return func(b *testing.B) { |
|
|
|
|
b.ReportAllocs() |
|
|
|
|
for i := 0; i < b.N; i++ { |
|
|
|
|
_, err := time.Parse(time.RFC3339Nano, in) |
|
|
|
|
if err != nil { |
|
|
|
|
b.Fatal(err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
b.Run("Z", run("2020-04-05T15:56:00.148487491Z")) |
|
|
|
|
b.Run("TZ", run("2020-04-05T15:56:00.148487491+08:00")) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func BenchmarkGoParse3339InLocation(b *testing.B) { |
|
|
|
|
@ -76,29 +123,34 @@ func BenchmarkGoParse3339InLocation(b *testing.B) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func BenchmarkParse3339(b *testing.B) { |
|
|
|
|
b.ReportAllocs() |
|
|
|
|
const in = `2020-04-05T15:56:00.148487491+08:00` |
|
|
|
|
run := func(in string) func(*testing.B) { |
|
|
|
|
return func(b *testing.B) { |
|
|
|
|
b.ReportAllocs() |
|
|
|
|
|
|
|
|
|
t, err := time.Parse(time.RFC3339Nano, in) |
|
|
|
|
if err != nil { |
|
|
|
|
b.Fatal(err) |
|
|
|
|
} |
|
|
|
|
t, err := time.Parse(time.RFC3339Nano, in) |
|
|
|
|
if err != nil { |
|
|
|
|
b.Fatal(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
t2, err := Parse3339(in) |
|
|
|
|
if err != nil { |
|
|
|
|
b.Fatal(err) |
|
|
|
|
} |
|
|
|
|
if !t.Equal(t2) { |
|
|
|
|
b.Fatal("not equal") |
|
|
|
|
} |
|
|
|
|
if s1, s2 := t.Format(time.RFC3339Nano), t2.Format(time.RFC3339Nano); s1 != s2 { |
|
|
|
|
b.Fatalf("times don't stringify the same: %q vs %q", s1, s2) |
|
|
|
|
} |
|
|
|
|
t2, err := Parse3339(in) |
|
|
|
|
if err != nil { |
|
|
|
|
b.Fatal(err) |
|
|
|
|
} |
|
|
|
|
if !t.Equal(t2) { |
|
|
|
|
b.Fatal("not equal") |
|
|
|
|
} |
|
|
|
|
if s1, s2 := t.Format(time.RFC3339Nano), t2.Format(time.RFC3339Nano); s1 != s2 { |
|
|
|
|
b.Fatalf("times don't stringify the same: %q vs %q", s1, s2) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for i := 0; i < b.N; i++ { |
|
|
|
|
_, err := Parse3339(in) |
|
|
|
|
if err != nil { |
|
|
|
|
b.Fatal(err) |
|
|
|
|
for i := 0; i < b.N; i++ { |
|
|
|
|
_, err := Parse3339(in) |
|
|
|
|
if err != nil { |
|
|
|
|
b.Fatal(err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
b.Run("Z", run("2020-04-05T15:56:00.148487491Z")) |
|
|
|
|
b.Run("TZ", run("2020-04-05T15:56:00.148487491+08:00")) |
|
|
|
|
} |
|
|
|
|
|