- 公開日
Goの日付フォーマット 〜<2006年1月2日>の謎〜
Goの現在時刻は time.Now()
で取得することができるが、フォーマットされた現在日時はどのように取得すればよいのだろうか?
今日の日付の取得
package main
import (
"fmt"
"time"
)
func main() {
// フォーマットなし現在時刻
fmt.Println(time.Now())
// フォーマットあり現在時刻
fmt.Println(time.Now().Format("2006年01月02日"))
}
これで今日の日付を取得することができる。
2009-11-10 23:00:00 +0000 UTC m=+0.000000001
2009年11月10日
2006年1月2日の謎
しかしここで1つの疑問が残る。Format()
の引数として与えられる 2006年01月02日
はどうして2006年1月2日なのだろうか? 2001年2月3日でもダメだし1234年5月6日でもダメだ。きっちり 2006年1月2日 でなければならない。
この理由については下記の記事で解説されている。
では一体この2006年1月2日という特別な日は、なんの日なのか?
(…中略…)
答えは単純だ。これはアメリカ式の時刻の順番なのだ。”1月2日午後3時4分5秒2006年”(つまり「自然な順番」で1, 2, 3, 4, 5, 6)を指しているのである。
via. Goのtimeパッケージのリファレンスタイム(2006年1月2日)は何の日? - Qiita
考えてみるとなんてことはない、アメリカ式の日時の表示順番でのインクリメンタルな自然数であった!
Goの内部実装を覗いてみる
もう少し深く理解するために、Goでどのように実装されているかを覗いてみる。それぞれのconst
がどの数値とマッピングするかがコメントで示されている。
const (
_ = iota
stdLongMonth = iota + stdNeedDate // "January"
stdMonth // "Jan"
stdNumMonth // "1"
stdZeroMonth // "01"
stdLongWeekDay // "Monday"
stdWeekDay // "Mon"
stdDay // "2"
stdUnderDay // "_2"
stdZeroDay // "02"
stdHour = iota + stdNeedClock // "15"
stdHour12 // "3"
stdZeroHour12 // "03"
stdMinute // "4"
stdZeroMinute // "04"
stdSecond // "5"
stdZeroSecond // "05"
stdLongYear = iota + stdNeedDate // "2006"
stdYear // "06"
stdPM = iota + stdNeedClock // "PM"
stdpm // "pm"
stdTZ = iota // "MST"
stdISO8601TZ // "Z0700" // prints Z for UTC
stdISO8601SecondsTZ // "Z070000"
stdISO8601ShortTZ // "Z07"
stdISO8601ColonTZ // "Z07:00" // prints Z for UTC
stdISO8601ColonSecondsTZ // "Z07:00:00"
stdNumTZ // "-0700" // always numeric
stdNumSecondsTz // "-070000"
stdNumShortTZ // "-07" // always numeric
stdNumColonTZ // "-07:00" // always numeric
stdNumColonSecondsTZ // "-07:00:00"
stdFracSecond0 // ".0", ".00", ... , trailing zeros included
stdFracSecond9 // ".9", ".99", ..., trailing zeros omitted
stdNeedDate = 1 << 8 // need month, day, year
stdNeedClock = 2 << 8 // need hour, minute, second
stdArgShift = 16 // extra argument in high bits, above low stdArgShift
stdMask = 1<<stdArgShift - 1 // mask out argument
)
via. go/format.go at master · golang/go
この実装をみると 2006-01-02
は {stdLongYear}-{stdZeroMonth}-{stdZeroDay}
であることがわかる。
Goの標準日付フォーマット
RFCなどの標準的な時刻フォーマットは、Goが標準で用意してくれている。
const (
ANSIC = "Mon Jan _2 15:04:05 2006"
UnixDate = "Mon Jan _2 15:04:05 MST 2006"
RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
RFC822 = "02 Jan 06 15:04 MST"
RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
RFC3339 = "2006-01-02T15:04:05Z07:00"
RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
Kitchen = "3:04PM"
// Handy time stamps.
Stamp = "Jan _2 15:04:05"
StampMilli = "Jan _2 15:04:05.000"
StampMicro = "Jan _2 15:04:05.000000"
StampNano = "Jan _2 15:04:05.000000000"
)
これを使って下記のように書くことができる。
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println(time.Now().Format(time.RFC822Z))
}
RFC822Z の形式で下記のように出力される。
10 Nov 09 23:00 +0000