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
에 씁니다.
미리 컴파일된 패턴에 따라 시간 형식을 지정하고 결과 문자열을 반환합니다.
무늬 | 설명 |
---|---|
%에이 | 전체 요일 이름의 국가별 표현 |
%에이 | 축약된 요일의 국가적 표현 |
%비 | 전체 월 이름의 국가별 표현 |
%비 | 약어로 된 월 이름의 국가 표현 |
%기음 | (연도/100)을 십진수로 표시합니다. 한 자리 숫자 앞에는 0이 옵니다. |
%기음 | 시간과 날짜의 국가별 표현 |
%디 | %m/%d/%y와 동일 |
%디 | 해당 월의 일을 10진수로 표시(01-31) |
%이자형 | 해당 월의 일자를 십진수(1-31)로 표시합니다. 한 자리 숫자 앞에는 공백이 옵니다. |
%에프 | %Y-%m-%d와 동일 |
%시간 | 십진수(00-23)로 표현된 시간(24시간제) |
%시간 | %b와 동일 |
%나 | 십진수(01-12)로 표현된 시간(12시간제) |
%j | 10진수로 된 날짜(001-366) |
%케이 | 시간(24시간제)을 십진수(0-23)로 표시합니다. 한 자리 숫자 앞에는 공백이 옵니다. |
%엘 | 십진수(1-12)로 표현된 시간(12시간제) 한 자리 숫자 앞에는 공백이 옵니다. |
%중 | 십진수로 표현된 분(00-59) |
%중 | 월을 십진수로 표시(01-12) |
%N | 개행 |
%피 | 적절하게 "ante meridiem"(am) 또는 "post meridiem"(pm)의 국가적 표현입니다. |
%아르 자형 | %H:%M과 동일 |
%아르 자형 | %I:%M:%S %p와 동일 |
%에스 | 초를 십진수로 표시(00-60) |
%티 | %H:%M:%S와 동일 |
%티 | 탭 |
%유 | 해당 연도의 주 번호(일요일은 주의 첫 번째 날)를 십진수(00-53)로 표시합니다. |
%유 | 평일(월요일은 주의 첫 번째 날)을 십진수(1-7)로 표시합니다. |
%다섯 | 해당 연도의 주 번호(월요일은 주의 첫 번째 날)를 십진수(01-53)로 표시합니다. |
%다섯 | %e-%b-%Y와 동일 |
%W | 해당 연도의 주 번호(월요일은 주의 첫 번째 날)를 십진수(00-53)로 표시합니다. |
%w | 주중(일요일의 첫 번째 날)을 십진수(0-6)로 표시합니다. |
%엑스 | 당시의 국가대표 |
%엑스 | 날짜의 국가적 표현 |
%와이 | 세기를 십진수로 표시한 연도 |
%와이 | 세기를 제외한 연도를 십진수로 표현(00-99) |
%지 | 시간대 이름 |
%지 | 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
).
일부 라이브러리가 특정 플랫폼(특히 fastly 버전)에서 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 | 3000000 | FormatString() 사용(캐시됨) |
github.com/fastly/go-utils/strftime | 2000000 | OS X의 Pure 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 | 500000 | Format() 사용(캐시됨) |
github.com/tebeka/strftime | 300000 |
그러나 패턴에 따라 이 속도는 달라질 수 있습니다. 느리게 보이는 특정 패턴을 발견하면 패치나 테스트를 보내주세요.
또한 이 벤치마크는 비교된 모든 라이브러리에서 지원하는 변환 사양의 하위 집합만 사용한다는 점에 유의하세요.
향후 성능 비교 시 고려해야 할 사항은 다음과 같습니다.
%specification
처리합니까?