]> Cypherpunks repositories - gostls13.git/commitdiff
time: optimize Format for RFC3339 and RFC3339Nano
authorAmarjeet Anand <amarjeetanandsingh@gmail.com>
Sun, 7 Aug 2022 18:19:19 +0000 (23:49 +0530)
committerGopher Robot <gobot@golang.org>
Thu, 11 Aug 2022 17:14:08 +0000 (17:14 +0000)
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>

src/time/format.go
src/time/time_test.go

index 61a9eb3301b78738429110f5dc8b3832c47716fc..721a207c0ef3e312e4b1171c362a86586dfed429 100644 (file)
@@ -626,6 +626,15 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
                min   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.
        for layout != "" {
                prefix, std, suffix := nextStdChunk(layout)
@@ -781,6 +790,48 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
        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
 
 // ParseError describes a problem parsing a time string.
index 6fde5f6470abdd485f7014985fa285e9a44854b6..059c71bb8a07d1a736050ffa66fb3e06cf70775f 100644 (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) {
        // Like BenchmarkFormat, but easier, because the time zone
        // lookup cache is optimized for the present.