2020-06-15 12:26:44 ,
https://git.io/Jf7gD in
lestrrat-go/strftime
Thanks for the quick review.
> The test tests against %L -- which is fine, because you're using 'L' as the symbol, but maybe it might throw the reader off why you're not using %f?
That was a copy-paste oversight. Fixed.
> "List of available extensions" in the README :)
Added. I also added links to autogenerated docs on pkg.go.dev, no sure if that's excessive for you.
2020-06-15 12:16:35 ,
https://git.io/Jf7gy in
lestrrat-go/strftime
Okay, I wrote some benchmarks
```diff
diff --git a/extension.go b/extension.go
index 77f947b..f1434a3 100644
--- a/extension.go
+++ b/extension.go
@@ -13,6 +13,7 @@ import (
// milliseconds function
var milliseconds Appender
var microseconds Appender
+var microsecondsAltImpl Appender
var unixseconds Appender
func init() {
@@ -36,6 +37,25 @@ func init() {
return append(b, strconv.Itoa(microsecond)...)
}
})
+ microsecondsAltImpl = AppendFunc(func(b []byte, t time.Time) []byte {
+ microsecond := int(t.Nanosecond()) / int(time.Microsecond)
+ if microsecond < 100000 {
+ b = append(b, '0')
+ }
+ if microsecond < 10000 {
+ b = append(b, '0')
+ }
+ if microsecond < 1000 {
+ b = append(b, '0')
+ }
+ if microsecond < 100 {
+ b = append(b, '0')
+ }
+ if microsecond < 10 {
+ b = append(b, '0')
+ }
+ return append(b, strconv.Itoa(microsecond)...)
+ })
unixseconds = AppendFunc(func(b []byte, t time.Time) []byte {
return append(b, strconv.FormatInt(t.Unix(), 10)...)
})
@@ -53,6 +73,10 @@ func Microseconds() Appender {
return microseconds
}
+func MicrosecondsAltImpl() Appender {
+ return microsecondsAltImpl
+}
+
// UnixSeconds returns the Appender suitable for creating
// unix timestamp textual representation.
func UnixSeconds() Appender {
diff --git a/options.go b/options.go
index 8ef9d95..1dca0e3 100644
--- a/options.go
+++ b/options.go
@@ -58,6 +58,10 @@ func WithMicroseconds(b byte) Option {
return WithSpecification(b, Microseconds())
}
+func WithMicrosecondsAltImpl(b byte) Option {
+ return WithSpecification(b, MicrosecondsAltImpl())
+}
+
// WithUnixSeconds is similar to WithSpecification, and specifies that
// the Strftime object should interpret the pattern `%b` (where b
// is the byte that you specify as the argument)
diff --git a/strftime_test.go b/strftime_test.go
index 30775dc..cf3424a 100644
--- a/strftime_test.go
+++ b/strftime_test.go
@@ -259,3 +259,17 @@ func TestGHIssue9(t *testing.T) {
return
}
}
+
+func BenchmarkMicrosecond(b *testing.B) {
+ p, _ := strftime.New(`%f`, strftime.WithMicroseconds('f'))
+ for n := 0; n < b.N; n++ {
+ p.FormatString(time.Now())
+ }
+}
+
+func BenchmarkMicrosecondAltImpl(b *testing.B) {
+ p, _ := strftime.New(`%f`, strftime.WithMicrosecondsAltImpl('f'))
+ for n := 0; n < b.N; n++ {
+ p.FormatString(time.Now())
+ }
+}
```
On my Mac:
```command
$ go test -bench=.
goos: darwin
goarch: amd64
pkg: github.com/lestrrat-go/strftime
BenchmarkMicrosecond-12 6844014 177 ns/op
BenchmarkMicrosecondAltImpl-12 8407060 142 ns/op
PASS
ok github.com/lestrrat-go/strftime 2.737s
```
On my Linux box:
```command
$ goos: linux
goarch: amd64
pkg: github.com/lestrrat-go/strftime
BenchmarkMicrosecond-2 8807217 137 ns/op
BenchmarkMicrosecondAltImpl-2 10977770 115 ns/op
PASS
ok github.com/lestrrat-go/strftime 2.725s
```
So apparently using simple branches is still faster than floating point math (replacing the `bytes.Repeat` with a straightforward loop helps a little but is still slower). I'll be switching over.