Goの日付フォーマットの謎
日付や日時を文字列に変換する方法を調べていて、Goは%Y-%m-%dではなく、"2006-01-02"というフォーマットを採用していることを知る。
年は「2006」、月は「01」、日は「02」と決まっている。
これは、「2016」、「12」、「31」ではいけないのである。
import time fmt.Println(time.Now()) // 2016-11-17 11:46:44.630877067 +0900 JST // わかる。 fmt.Println(time.Now().Format("2006/01/02")) // => 2016/11/17 // なぜなのか? fmt.Println(time.Now().Format("2016/12/31")) // => 17116/1117/1111 fmt.Println(time.Now().Format("2005/01/02")) // => 17044/11/17
ここに各種トークンの意味が定義されている
https://golang.org/src/time/format.go
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 )
非常に不運なことに、わたしはこのサンプルコードを11月17日の午前11時に動かしていたため、「11」と「17」が不規則に並んで出力され(!)、ことさら混乱を招いた。
ちなみに、11月11日は日本を代表する歌手である吉幾三さんの誕生日である。
"2005"を指定すると、「2:日」+「0:無視」+「05:秒」と解釈される。
よって、「17(日)」+「(空文字列)」+「044(秒)」=「17044」となる。
同様に、"2016"は「2:日」+「01:月」+「6(末尾文字はそのまま結合)」解釈され、「17」+「11」+「6」=「17116」となるのである。
はっきり言って、%Y-%m-%dの方が慣れているのでわかりやすい*1。
なまじ具体的な日時の値に即したフォーマットなので、任意の日時を書式指定するとうまく解釈してくれるものと誤解してしまった。
*1:所詮、わかりやすい理由は「慣れているから」にすぎないから、新たに慣れれば良いだけなのだが。