1
0
mirror of https://github.com/golang/go synced 2024-11-23 00:10:07 -07:00

time: optimize Format for RFC3339 and RFC3339Nano

Optimise Format for the most frequently used RFC3339
and RFC3339Nano layouts by avoiding parsing of layout.

> benchstat oldBench.txt newBench.txt
name                 old time/op    new time/op    delta
FormatRFC3339-8         302ns ± 1%     203ns ± 0%  -32.89%  (p=0.016 n=5+4)
FormatRFC3339Nano-8     337ns ± 1%     219ns ± 1%  -34.91%  (p=0.008 n=5+5)

name                 old alloc/op   new alloc/op   delta
FormatRFC3339-8         32.0B ± 0%     32.0B ± 0%     ~     (all equal)
FormatRFC3339Nano-8     32.0B ± 0%     32.0B ± 0%     ~     (all equal)

name                 old allocs/op  new allocs/op  delta
FormatRFC3339-8          1.00 ± 0%      1.00 ± 0%     ~     (all equal)
FormatRFC3339Nano-8      1.00 ± 0%      1.00 ± 0%     ~     (all equal)

Fixes #54093

Change-Id: Ifc84fce6078e24514ecbcd234875bca4aaab5e0e
Reviewed-on: https://go-review.googlesource.com/c/go/+/421877
Run-TryBot: Ian Lance Taylor <iant@google.com>
Auto-Submit: Joseph Tsai <joetsai@digital-static.net>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Joseph Tsai <joetsai@digital-static.net>
Run-TryBot: Joseph Tsai <joetsai@digital-static.net>
This commit is contained in:
Amarjeet Anand 2022-08-07 23:49:19 +05:30 committed by Gopher Robot
parent 8298c545f3
commit 133c0e9011
2 changed files with 65 additions and 0 deletions

View File

@ -626,6 +626,15 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
min int min int
sec int sec int
) )
// Handle most frequent layouts separately.
switch layout {
case RFC3339:
return t.appendFormatRFC3339(b, abs, offset, false)
case RFC3339Nano:
return t.appendFormatRFC3339(b, abs, offset, true)
}
// Each iteration generates one std value. // Each iteration generates one std value.
for layout != "" { for layout != "" {
prefix, std, suffix := nextStdChunk(layout) prefix, std, suffix := nextStdChunk(layout)
@ -781,6 +790,48 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
return b return b
} }
func (t Time) appendFormatRFC3339(b []byte, abs uint64, offset int, nanos bool) []byte {
// Format date.
year, month, day, _ := absDate(abs, true)
b = appendInt(b, year, 4)
b = append(b, '-')
b = appendInt(b, int(month), 2)
b = append(b, '-')
b = appendInt(b, day, 2)
b = append(b, 'T')
// Format time.
hour, min, sec := absClock(abs)
b = appendInt(b, hour, 2)
b = append(b, ':')
b = appendInt(b, min, 2)
b = append(b, ':')
b = appendInt(b, sec, 2)
if nanos {
std := stdFracSecond(stdFracSecond9, 9, '.')
b = formatNano(b, uint(t.Nanosecond()), std)
}
if offset == 0 {
return append(b, 'Z')
}
// Format zone.
zone := offset / 60 // convert to minutes
if zone < 0 {
b = append(b, '-')
zone = -zone
} else {
b = append(b, '+')
}
b = appendInt(b, zone/60, 2)
b = append(b, ':')
b = appendInt(b, zone%60, 2)
return b
}
var errBad = errors.New("bad value for field") // placeholder not passed to user var errBad = errors.New("bad value for field") // placeholder not passed to user
// ParseError describes a problem parsing a time string. // ParseError describes a problem parsing a time string.

View File

@ -1402,6 +1402,20 @@ func BenchmarkFormat(b *testing.B) {
} }
} }
func BenchmarkFormatRFC3339(b *testing.B) {
t := Unix(1265346057, 0)
for i := 0; i < b.N; i++ {
t.Format("2006-01-02T15:04:05Z07:00")
}
}
func BenchmarkFormatRFC3339Nano(b *testing.B) {
t := Unix(1265346057, 0)
for i := 0; i < b.N; i++ {
t.Format("2006-01-02T15:04:05.999999999Z07:00")
}
}
func BenchmarkFormatNow(b *testing.B) { func BenchmarkFormatNow(b *testing.B) {
// Like BenchmarkFormat, but easier, because the time zone // Like BenchmarkFormat, but easier, because the time zone
// lookup cache is optimized for the present. // lookup cache is optimized for the present.