Go 的快速 strftime
f , err := strftime . New ( `.... pattern ...` )
if err := f . Format ( buf , time . Now ()); err != nil {
log . Println ( err . Error ())
}
该库的目标是
获取模式和时间,并格式化它。该函数是一个实用函数,每次调用该函数时都会重新编译模式。如果您事先知道将多次格式化相同的模式,请考虑使用New
创建Strftime
对象并重用它。
采用该模式并创建一个新的Strftime
对象。
返回用于创建此Strftime
对象的模式字符串
根据预编译的模式格式化时间,并将结果写入指定的io.Writer
根据预编译模式格式化时间,并返回结果字符串。
图案 | 描述 |
---|---|
%一个 | 完整工作日名称的国家代表性 |
%一个 | 缩写工作日的全国代表性 |
%B | 完整月份名称的国家代表 |
%b | 缩写月份名称的国家表示 |
%C | (年/100)作为十进制数;个位数前面有一个零 |
%c | 时间和日期的国家表示 |
%D | 相当于%m/%d/%y |
%d | 十进制数形式的月份日期 (01-31) |
%e | 以十进制数表示的月份日期 (1-31);个位数前面有一个空格 |
%F | 相当于%Y-%m-%d |
%H | 十进制数 (00-23) 形式的小时(24 小时制) |
%h | 与%b相同 |
%我 | 十进制数形式的小时(12 小时制)(01-12) |
%j | 十进制数形式的一年中的第几天 (001-366) |
%k | 十进制数 (0-23) 形式的小时(24 小时制);个位数前面有一个空格 |
%l | 十进制数 (1-12) 形式的小时(12 小时制);个位数前面有一个空格 |
%M | 十进制数形式的分钟 (00-59) |
%m | 十进制数形式的月份 (01-12) |
%n | 换行符 |
%p | 酌情“午前”(am) 或“午后”(pm) 的国家代表性。 |
%R | 相当于%H:%M |
%r | 相当于 %I:%M:%S %p |
%S | 第二个十进制数 (00-60) |
%T | 相当于 %H:%M:%S |
%t | 一个选项卡 |
%U | 一年中的周数(星期日为一周的第一天),十进制数 (00-53) |
%u | 工作日(星期一为一周的第一天)十进制数 (1-7) |
%V | 一年中的周数(星期一为一周的第一天),十进制数 (01-53) |
%v | 相当于%e-%b-%Y |
%W | 一年中的周数(星期一为一周的第一天),十进制数 (00-53) |
%w | 工作日(星期日为一周的第一天)十进制数 (0-6) |
%X | 当时的国家代表 |
%x | 日期的国家代表 |
%Y | 以十进制数表示的年份 |
%y | 不带世纪的十进制年份 (00-99) |
%Z | 时区名称 |
%z | 与 UTC 的时区偏移量 |
%% | 一个“%” |
该库通常会尝试兼容 POSIX,但有时您只需要一两个相对广泛使用但未包含在 POSIX 规范中的额外规范。
例如,POSIX 没有指定如何打印毫秒,但流行的实现允许%f
或%L
来实现这一点。
对于这些实例, strftime.Strftime
可以配置为使用一组自定义规范:
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())
实现必须实现Appender
接口,即
type Appender interface {
Append([]byte, time.Time) []byte
}
对于常用的扩展(例如毫秒示例和 Unix 时间戳),我们提供了默认实现,以便用户可以执行以下操作之一:
// (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'),
)
对于 Unix 时间戳同样如此:
// (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'),
)
如果缺少通用规范,请随时提交 PR(但请务必能够捍卫它的“通用性”)
Milliseconds
(相关选项: WithMilliseconds
);
Microseconds
(相关选项: WithMicroseconds
);
UnixSeconds
(相关选项: WithUnixSeconds
)。
以下基准测试是单独运行的,因为一些库在特定平台上使用 cgo(值得注意的是,快速版本)
// 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
如果您可以重用格式模式,则该库比其他库快得多。
这是基准测试结果的带注释列表。您可以清楚地看到,(重新)使用Strftime
对象并生成字符串是最快的。写入io.Writer
似乎有点缓慢,但由于生成字符串的人正在做几乎完全相同的事情,我们相信这纯粹是写入io.Writer
的开销
导入路径 | 分数 | 笔记 |
---|---|---|
github.com/lestrrat-go/strftime | 300万 | 使用FormatString() (缓存) |
github.com/fastly/go-utils/strftime | 2000000 | OS X 上的纯 go 版本 |
github.com/lestrrat-go/strftime | 1000000 | 使用Format() (不缓存) |
github.com/jehiah/go-strftime | 1000000 | |
github.com/fastly/go-utils/strftime | 1000000 | Linux 上的 cgo 版本 |
github.com/lestrrat-go/strftime | 50万 | 使用Format() (缓存) |
github.com/tebeka/strftime | 30万 |
但是,根据您的模式,此速度可能会有所不同。如果您发现某个特定模式似乎运行缓慢,请发送补丁或测试。
另请注意,此基准测试仅使用所有比较库支持的转换规范子集。
将来进行性能比较时需要考虑的事项:
%specification
?