You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tailscale/tstime/tstime_test.go

156 lines
3.8 KiB
Go

// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package tstime
import (
"testing"
"time"
)
tstime: write Parse3339 parse that doesn't use time.Parse It doesn't allocate and it's half the time of time.Parse (which allocates), and 2/3rds the time of time.ParseInLocation (which doesn't). Go with a UTC time: BenchmarkGoParse3339/Z-8 2200995 534 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2254816 554 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2159504 522 ns/op 0 B/op 0 allocs/op Go allocates with a "-08:00" suffix instead of ending in "Z": BenchmarkGoParse3339/TZ-8 1276491 884 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1355858 942 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1385484 911 ns/op 144 B/op 3 allocs/op Go doesn't allocate if you use time.ParseInLocation, but then you need to parse the string to find the location anyway, so might as well go all the way (below). BenchmarkGoParse3339InLocation-8 1912254 597 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1980043 612 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1891366 612 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, UTC: BenchmarkParse3339/Z-8 3889220 307 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3718500 309 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3621231 303 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, with timezone (w/ *time.Location fetched from sync.Map) BenchmarkParse3339/TZ-8 3019612 418 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 2921618 401 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 3031671 408 ns/op 0 B/op 0 allocs/op Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
5 years ago
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.Fatalf("for %q, go err = %v; our err = %v", s, goErr, err)
tstime: write Parse3339 parse that doesn't use time.Parse It doesn't allocate and it's half the time of time.Parse (which allocates), and 2/3rds the time of time.ParseInLocation (which doesn't). Go with a UTC time: BenchmarkGoParse3339/Z-8 2200995 534 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2254816 554 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2159504 522 ns/op 0 B/op 0 allocs/op Go allocates with a "-08:00" suffix instead of ending in "Z": BenchmarkGoParse3339/TZ-8 1276491 884 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1355858 942 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1385484 911 ns/op 144 B/op 3 allocs/op Go doesn't allocate if you use time.ParseInLocation, but then you need to parse the string to find the location anyway, so might as well go all the way (below). BenchmarkGoParse3339InLocation-8 1912254 597 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1980043 612 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1891366 612 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, UTC: BenchmarkParse3339/Z-8 3889220 307 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3718500 309 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3621231 303 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, with timezone (w/ *time.Location fetched from sync.Map) BenchmarkParse3339/TZ-8 3019612 418 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 2921618 401 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 3031671 408 ns/op 0 B/op 0 allocs/op Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
5 years ago
}
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
}{
{"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"},
{"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"},
tstime: write Parse3339 parse that doesn't use time.Parse It doesn't allocate and it's half the time of time.Parse (which allocates), and 2/3rds the time of time.ParseInLocation (which doesn't). Go with a UTC time: BenchmarkGoParse3339/Z-8 2200995 534 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2254816 554 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2159504 522 ns/op 0 B/op 0 allocs/op Go allocates with a "-08:00" suffix instead of ending in "Z": BenchmarkGoParse3339/TZ-8 1276491 884 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1355858 942 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1385484 911 ns/op 144 B/op 3 allocs/op Go doesn't allocate if you use time.ParseInLocation, but then you need to parse the string to find the location anyway, so might as well go all the way (below). BenchmarkGoParse3339InLocation-8 1912254 597 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1980043 612 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1891366 612 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, UTC: BenchmarkParse3339/Z-8 3889220 307 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3718500 309 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3621231 303 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, with timezone (w/ *time.Location fetched from sync.Map) BenchmarkParse3339/TZ-8 3019612 418 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 2921618 401 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 3031671 408 ns/op 0 B/op 0 allocs/op Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
5 years ago
{"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 {
t.Errorf("zoneOf(%q) = %q; want %q", tt.in, got, tt.want)
}
}
}
func BenchmarkGoParse3339(b *testing.B) {
tstime: write Parse3339 parse that doesn't use time.Parse It doesn't allocate and it's half the time of time.Parse (which allocates), and 2/3rds the time of time.ParseInLocation (which doesn't). Go with a UTC time: BenchmarkGoParse3339/Z-8 2200995 534 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2254816 554 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2159504 522 ns/op 0 B/op 0 allocs/op Go allocates with a "-08:00" suffix instead of ending in "Z": BenchmarkGoParse3339/TZ-8 1276491 884 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1355858 942 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1385484 911 ns/op 144 B/op 3 allocs/op Go doesn't allocate if you use time.ParseInLocation, but then you need to parse the string to find the location anyway, so might as well go all the way (below). BenchmarkGoParse3339InLocation-8 1912254 597 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1980043 612 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1891366 612 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, UTC: BenchmarkParse3339/Z-8 3889220 307 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3718500 309 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3621231 303 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, with timezone (w/ *time.Location fetched from sync.Map) BenchmarkParse3339/TZ-8 3019612 418 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 2921618 401 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 3031671 408 ns/op 0 B/op 0 allocs/op Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
5 years ago
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)
}
}
}
}
tstime: write Parse3339 parse that doesn't use time.Parse It doesn't allocate and it's half the time of time.Parse (which allocates), and 2/3rds the time of time.ParseInLocation (which doesn't). Go with a UTC time: BenchmarkGoParse3339/Z-8 2200995 534 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2254816 554 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2159504 522 ns/op 0 B/op 0 allocs/op Go allocates with a "-08:00" suffix instead of ending in "Z": BenchmarkGoParse3339/TZ-8 1276491 884 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1355858 942 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1385484 911 ns/op 144 B/op 3 allocs/op Go doesn't allocate if you use time.ParseInLocation, but then you need to parse the string to find the location anyway, so might as well go all the way (below). BenchmarkGoParse3339InLocation-8 1912254 597 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1980043 612 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1891366 612 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, UTC: BenchmarkParse3339/Z-8 3889220 307 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3718500 309 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3621231 303 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, with timezone (w/ *time.Location fetched from sync.Map) BenchmarkParse3339/TZ-8 3019612 418 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 2921618 401 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 3031671 408 ns/op 0 B/op 0 allocs/op Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
5 years ago
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) {
b.ReportAllocs()
const in = `2020-04-05T15:56:00.148487491+08:00`
t, err := time.Parse(time.RFC3339Nano, in)
if err != nil {
b.Fatal(err)
}
loc := t.Location()
t2, err := time.ParseInLocation(time.RFC3339Nano, in, loc)
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 := time.ParseInLocation(time.RFC3339Nano, in, loc)
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkParse3339(b *testing.B) {
tstime: write Parse3339 parse that doesn't use time.Parse It doesn't allocate and it's half the time of time.Parse (which allocates), and 2/3rds the time of time.ParseInLocation (which doesn't). Go with a UTC time: BenchmarkGoParse3339/Z-8 2200995 534 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2254816 554 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2159504 522 ns/op 0 B/op 0 allocs/op Go allocates with a "-08:00" suffix instead of ending in "Z": BenchmarkGoParse3339/TZ-8 1276491 884 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1355858 942 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1385484 911 ns/op 144 B/op 3 allocs/op Go doesn't allocate if you use time.ParseInLocation, but then you need to parse the string to find the location anyway, so might as well go all the way (below). BenchmarkGoParse3339InLocation-8 1912254 597 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1980043 612 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1891366 612 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, UTC: BenchmarkParse3339/Z-8 3889220 307 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3718500 309 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3621231 303 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, with timezone (w/ *time.Location fetched from sync.Map) BenchmarkParse3339/TZ-8 3019612 418 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 2921618 401 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 3031671 408 ns/op 0 B/op 0 allocs/op Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
5 years ago
run := func(in string) func(*testing.B) {
return func(b *testing.B) {
b.ReportAllocs()
tstime: write Parse3339 parse that doesn't use time.Parse It doesn't allocate and it's half the time of time.Parse (which allocates), and 2/3rds the time of time.ParseInLocation (which doesn't). Go with a UTC time: BenchmarkGoParse3339/Z-8 2200995 534 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2254816 554 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2159504 522 ns/op 0 B/op 0 allocs/op Go allocates with a "-08:00" suffix instead of ending in "Z": BenchmarkGoParse3339/TZ-8 1276491 884 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1355858 942 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1385484 911 ns/op 144 B/op 3 allocs/op Go doesn't allocate if you use time.ParseInLocation, but then you need to parse the string to find the location anyway, so might as well go all the way (below). BenchmarkGoParse3339InLocation-8 1912254 597 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1980043 612 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1891366 612 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, UTC: BenchmarkParse3339/Z-8 3889220 307 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3718500 309 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3621231 303 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, with timezone (w/ *time.Location fetched from sync.Map) BenchmarkParse3339/TZ-8 3019612 418 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 2921618 401 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 3031671 408 ns/op 0 B/op 0 allocs/op Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
5 years ago
t, err := time.Parse(time.RFC3339Nano, in)
if err != nil {
b.Fatal(err)
}
tstime: write Parse3339 parse that doesn't use time.Parse It doesn't allocate and it's half the time of time.Parse (which allocates), and 2/3rds the time of time.ParseInLocation (which doesn't). Go with a UTC time: BenchmarkGoParse3339/Z-8 2200995 534 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2254816 554 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2159504 522 ns/op 0 B/op 0 allocs/op Go allocates with a "-08:00" suffix instead of ending in "Z": BenchmarkGoParse3339/TZ-8 1276491 884 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1355858 942 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1385484 911 ns/op 144 B/op 3 allocs/op Go doesn't allocate if you use time.ParseInLocation, but then you need to parse the string to find the location anyway, so might as well go all the way (below). BenchmarkGoParse3339InLocation-8 1912254 597 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1980043 612 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1891366 612 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, UTC: BenchmarkParse3339/Z-8 3889220 307 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3718500 309 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3621231 303 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, with timezone (w/ *time.Location fetched from sync.Map) BenchmarkParse3339/TZ-8 3019612 418 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 2921618 401 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 3031671 408 ns/op 0 B/op 0 allocs/op Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
5 years ago
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)
}
tstime: write Parse3339 parse that doesn't use time.Parse It doesn't allocate and it's half the time of time.Parse (which allocates), and 2/3rds the time of time.ParseInLocation (which doesn't). Go with a UTC time: BenchmarkGoParse3339/Z-8 2200995 534 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2254816 554 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2159504 522 ns/op 0 B/op 0 allocs/op Go allocates with a "-08:00" suffix instead of ending in "Z": BenchmarkGoParse3339/TZ-8 1276491 884 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1355858 942 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1385484 911 ns/op 144 B/op 3 allocs/op Go doesn't allocate if you use time.ParseInLocation, but then you need to parse the string to find the location anyway, so might as well go all the way (below). BenchmarkGoParse3339InLocation-8 1912254 597 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1980043 612 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1891366 612 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, UTC: BenchmarkParse3339/Z-8 3889220 307 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3718500 309 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3621231 303 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, with timezone (w/ *time.Location fetched from sync.Map) BenchmarkParse3339/TZ-8 3019612 418 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 2921618 401 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 3031671 408 ns/op 0 B/op 0 allocs/op Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
5 years ago
for i := 0; i < b.N; i++ {
_, err := Parse3339(in)
if err != nil {
b.Fatal(err)
}
}
}
}
tstime: write Parse3339 parse that doesn't use time.Parse It doesn't allocate and it's half the time of time.Parse (which allocates), and 2/3rds the time of time.ParseInLocation (which doesn't). Go with a UTC time: BenchmarkGoParse3339/Z-8 2200995 534 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2254816 554 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339/Z-8 2159504 522 ns/op 0 B/op 0 allocs/op Go allocates with a "-08:00" suffix instead of ending in "Z": BenchmarkGoParse3339/TZ-8 1276491 884 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1355858 942 ns/op 144 B/op 3 allocs/op BenchmarkGoParse3339/TZ-8 1385484 911 ns/op 144 B/op 3 allocs/op Go doesn't allocate if you use time.ParseInLocation, but then you need to parse the string to find the location anyway, so might as well go all the way (below). BenchmarkGoParse3339InLocation-8 1912254 597 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1980043 612 ns/op 0 B/op 0 allocs/op BenchmarkGoParse3339InLocation-8 1891366 612 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, UTC: BenchmarkParse3339/Z-8 3889220 307 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3718500 309 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/Z-8 3621231 303 ns/op 0 B/op 0 allocs/op Parsing RFC3339 ourselves, with timezone (w/ *time.Location fetched from sync.Map) BenchmarkParse3339/TZ-8 3019612 418 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 2921618 401 ns/op 0 B/op 0 allocs/op BenchmarkParse3339/TZ-8 3031671 408 ns/op 0 B/op 0 allocs/op Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
5 years ago
b.Run("Z", run("2020-04-05T15:56:00.148487491Z"))
b.Run("TZ", run("2020-04-05T15:56:00.148487491+08:00"))
}