Categorygithub.com/lestrrat-go/strftime
modulepackage
1.1.0
Repository: https://github.com/lestrrat-go/strftime.git
Documentation: pkg.go.dev

# README

strftime

Fast strftime for Go

Build Status

GoDoc

SYNOPSIS

f, err := strftime.New(`.... pattern ...`)
if err := f.Format(buf, time.Now()); err != nil {
    log.Println(err.Error())
}

DESCRIPTION

The goals for this library are

  • Optimized for the same pattern being called repeatedly
  • Be flexible about destination to write the results out
  • Be as complete as possible in terms of conversion specifications

API

Format(string, time.Time) (string, error)

Takes the pattern and the time, and formats it. This function is a utility function that recompiles the pattern every time the function is called. If you know beforehand that you will be formatting the same pattern multiple times, consider using New to create a Strftime object and reuse it.

New(string) (*Strftime, error)

Takes the pattern and creates a new Strftime object.

obj.Pattern() string

Returns the pattern string used to create this Strftime object

obj.Format(io.Writer, time.Time) error

Formats the time according to the pre-compiled pattern, and writes the result to the specified io.Writer

obj.FormatString(time.Time) string

Formats the time according to the pre-compiled pattern, and returns the result string.

SUPPORTED CONVERSION SPECIFICATIONS

patterndescription
%Anational representation of the full weekday name
%anational representation of the abbreviated weekday
%Bnational representation of the full month name
%bnational representation of the abbreviated month name
%C(year / 100) as decimal number; single digits are preceded by a zero
%cnational representation of time and date
%Dequivalent to %m/%d/%y
%dday of the month as a decimal number (01-31)
%ethe day of the month as a decimal number (1-31); single digits are preceded by a blank
%Fequivalent to %Y-%m-%d
%Hthe hour (24-hour clock) as a decimal number (00-23)
%hsame as %b
%Ithe hour (12-hour clock) as a decimal number (01-12)
%jthe day of the year as a decimal number (001-366)
%kthe hour (24-hour clock) as a decimal number (0-23); single digits are preceded by a blank
%lthe hour (12-hour clock) as a decimal number (1-12); single digits are preceded by a blank
%Mthe minute as a decimal number (00-59)
%mthe month as a decimal number (01-12)
%na newline
%pnational representation of either "ante meridiem" (a.m.) or "post meridiem" (p.m.) as appropriate.
%Requivalent to %H:%M
%requivalent to %I:%M:%S %p
%Sthe second as a decimal number (00-60)
%Tequivalent to %H:%M:%S
%ta tab
%Uthe week number of the year (Sunday as the first day of the week) as a decimal number (00-53)
%uthe weekday (Monday as the first day of the week) as a decimal number (1-7)
%Vthe week number of the year (Monday as the first day of the week) as a decimal number (01-53)
%vequivalent to %e-%b-%Y
%Wthe week number of the year (Monday as the first day of the week) as a decimal number (00-53)
%wthe weekday (Sunday as the first day of the week) as a decimal number (0-6)
%Xnational representation of the time
%xnational representation of the date
%Ythe year with century as a decimal number
%ythe year without century as a decimal number (00-99)
%Zthe time zone name
%zthe time zone offset from UTC
%%a '%'

EXTENSIONS / CUSTOM SPECIFICATIONS

This library in general tries to be POSIX compliant, but sometimes you just need that extra specification or two that is relatively widely used but is not included in the POSIX specification.

For example, POSIX does not specify how to print out milliseconds, but popular implementations allow %f or %L to achieve this.

For those instances, strftime.Strftime can be configured to use a custom set of specifications:

ss := strftime.NewSpecificationSet()
ss.Set('L', ...) // provide implementation for `%L`

// pass this new specification set to the strftime instance
p, err := strftime.New(`%L`, strftime.WithSpecificationSet(ss))
p.Format(..., time.Now())

The implementation must implement the Appender interface, which is

type Appender interface {
  Append([]byte, time.Time) []byte
}

For commonly used extensions such as the millisecond example and Unix timestamp, we provide a default implementation so the user can do one of the following:

// (1) Pass a specification byte and the Appender
//     This allows you to pass arbitrary Appenders
p, err := strftime.New(
  `%L`,
  strftime.WithSpecification('L', strftime.Milliseconds),
)

// (2) Pass an option that knows to use strftime.Milliseconds
p, err := strftime.New(
  `%L`,
  strftime.WithMilliseconds('L'),
)

Similarly for Unix Timestamp:

// (1) Pass a specification byte and the Appender
//     This allows you to pass arbitrary Appenders
p, err := strftime.New(
  `%s`,
  strftime.WithSpecification('s', strftime.UnixSeconds),
)

// (2) Pass an option that knows to use strftime.UnixSeconds
p, err := strftime.New(
  `%s`,
  strftime.WithUnixSeconds('s'),
)

If a common specification is missing, please feel free to submit a PR (but please be sure to be able to defend how "common" it is)

List of available extensions

PERFORMANCE / OTHER LIBRARIES

The following benchmarks were run separately because some libraries were using cgo on specific platforms (notabley, the fastly version)

// On my OS X 10.14.6, 2.3 GHz Intel Core i5, 16GB memory.
// go version go1.13.4 darwin/amd64
hummingbird% go test -tags bench -benchmem -bench .
<snip>
BenchmarkTebeka-4                 	  297471	      3905 ns/op	     257 B/op	      20 allocs/op
BenchmarkJehiah-4                 	  818444	      1773 ns/op	     256 B/op	      17 allocs/op
BenchmarkFastly-4                 	 2330794	       550 ns/op	      80 B/op	       5 allocs/op
BenchmarkLestrrat-4               	  916365	      1458 ns/op	      80 B/op	       2 allocs/op
BenchmarkLestrratCachedString-4   	 2527428	       546 ns/op	     128 B/op	       2 allocs/op
BenchmarkLestrratCachedWriter-4   	  537422	      2155 ns/op	     192 B/op	       3 allocs/op
PASS
ok  	github.com/lestrrat-go/strftime	25.618s
// On a host on Google Cloud Platform, machine-type: f1-micro (vCPU x 1, memory: 0.6GB)
// (Yes, I was being skimpy)
// Linux <snip> 4.9.0-11-amd64 #1 SMP Debian 4.9.189-3+deb9u1 (2019-09-20) x86_64 GNU/Linux
// go version go1.13.4 linux/amd64
hummingbird% go test -tags bench -benchmem -bench .
<snip>
BenchmarkTebeka                   254997              4726 ns/op             256 B/op         20 allocs/op
BenchmarkJehiah                   659289              1882 ns/op             256 B/op         17 allocs/op
BenchmarkFastly                   389150              3044 ns/op             224 B/op         13 allocs/op
BenchmarkLestrrat                 699069              1780 ns/op              80 B/op          2 allocs/op
BenchmarkLestrratCachedString    2081594               589 ns/op             128 B/op          2 allocs/op
BenchmarkLestrratCachedWriter     825763              1480 ns/op             192 B/op          3 allocs/op
PASS
ok      github.com/lestrrat-go/strftime 11.355s

This library is much faster than other libraries IF you can reuse the format pattern.

Here's the annotated list from the benchmark results. You can clearly see that (re)using a Strftime object and producing a string is the fastest. Writing to an io.Writer seems a bit sluggish, but since the one producing the string is doing almost exactly the same thing, we believe this is purely the overhead of writing to an io.Writer

Import PathScoreNote
github.com/lestrrat-go/strftime3000000Using FormatString() (cached)
github.com/fastly/go-utils/strftime2000000Pure go version on OS X
github.com/lestrrat-go/strftime1000000Using Format() (NOT cached)
github.com/jehiah/go-strftime1000000
github.com/fastly/go-utils/strftime1000000cgo version on Linux
github.com/lestrrat-go/strftime500000Using Format() (cached)
github.com/tebeka/strftime300000

However, depending on your pattern, this speed may vary. If you find a particular pattern that seems sluggish, please send in patches or tests.

Please also note that this benchmark only uses the subset of conversion specifications that are supported by ALL of the libraries compared.

Somethings to consider when making performance comparisons in the future:

  • Can it write to io.Writer?
  • Which %specification does it handle?

# Functions

Format takes the format `s` and the time `t` to produce the format date/time.
Microsecond returns the Appender suitable for creating a zero-padded, 6-digit microsecond textual representation.
Milliseconds returns the Appender suitable for creating a zero-padded, 3-digit millisecond textual representation.
New creates a new Strftime object.
NewSpecificationSet creates a specification set with the default specifications.
StdlibFormat returns an Appender that simply goes through `time.Format()` For example, if you know you want to display the abbreviated month name for %b, you can create a StdlibFormat with the pattern `Jan` and register that for specification `b`: a := StdlibFormat(`Jan`) ss := NewSpecificationSet() ss.Set('b', a) // does %b -> abbreviated month name.
UnixSeconds returns the Appender suitable for creating unix timestamp textual representation.
Verbatim returns an Appender suitable for generating static text.
WithMicroseconds 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) as the zero-padded, 3 letter microseconds of the time.
WithMilliseconds 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) as the zero-padded, 3 letter milliseconds of the time.
WithSpecification allows you to create a new specification set on the fly, to be used only for that invocation.
WithSpecification allows you to specify a custom specification set.
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) as the unix timestamp in seconds.

# Structs

Strftime is the object that represents a compiled strftime pattern.

# Interfaces

Appender is the interface that must be fulfilled by components that implement the translation of specifications to actual time value.
No description provided by the author
SpecificationSet is a container for patterns that Strftime uses.

# Type aliases

AppendFunc is an utility type to allow users to create a function-only version of an Appender.