Golangで日付のフォーマット
Go言語の time
パッケージのフォーマットの扱いには少し慣れが必要なので、こちらでまとめておく。
# 日付を文字列にフォーマットする
# 基本的なフォーマットの仕方
日付を文字列にする際、Go言語の場合は下記のように、2006-01-02 15:04:05 -07:00(MST)
の場合の具体的な日付でフォーマットの指定を行う。
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
fmt.Println(string(t.Format("2006-01-02 15:04:05")),"\n") // 2022-01-05 14:57:24
}
2
3
4
5
6
7
8
9
10
なぜこのような日付なのかというと、アメリカ式の下記のフォーマットで1,2,3と順番に数値を当てはめていったらこうなった、ということのようである。
Layout = "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order.
# 使えるフォーマットの種類
time/format.go (opens new window)にはさまざまなフォーマットの指定があるのでそちらを読むのがわかりやすいと思うが、それでも個人的には少しわかりにくい気がしているので、ここでざっくりとまとめておく。
フォーマット | 説明 | |
---|---|---|
年 | 2006 | 年。4桁の数字。 |
06 | 年。下2桁の数字。 | |
月 | 1 | 月。数字。先頭にゼロをつけない。 |
01 | 月。数字。先頭にゼロをつける。 | |
Jan | 月。3文字。 | |
January | 月。フルスペル。 | |
日 | 2 | 日。先頭にゼロをつけない。 |
02 | 日。先頭にゼロをつける。 | |
_2 | 日。1桁の場合は先頭にスペース追加 | |
曜日 | Mon | 曜日。3文字。 |
Monday | 曜日。フルスペル。 | |
Monday | 曜日。フルスペル。 | |
時 | 15 | 時間。24時間表記。先頭にゼロをつける。 |
03 | 時間。12時間表記。先頭にゼロをつける。 | |
3 | 時間。12時間表記。先頭にゼロをつけない。 | |
PM | 午前ならAM、午後ならPM | |
pm | 午前ならam、午後ならpm | |
分 | 04 | 分。先頭にゼロをつける。 |
4 | 分。先頭にゼロをつけない。 | |
秒 | 05 | 秒。先頭にゼロをつける。 |
5 | 秒。先頭にゼロをつけない。 | |
タイムゾーン | MST | タイムゾーンの名前。日本の場合は(Asia/Tokyoではなく)JST |
Z0700 | 時差表記。日本の場合、"+0900" だが、UTCの場合は"Z"となる。 | |
Z07:00 | 時差表記。日本の場合、"+09:00" だが、UTCの場合は"Z"となる。 | |
-07:00 | タイムゾーン。日本の場合、"+09:00" | |
-0700 | タイムゾーン。日本の場合、"+0900" | |
-07 | タイムゾーン。日本の場合、"+09" |
ちなみに24時間における0時の場合12 AM
となり、12時の場合12 PM
という扱いになるので、日本人の(少なくとも私自身の)直感とは微妙に異なっている気がする。(個人的には0〜12時はAMのほうが自然な感じがするが、そうなるとAMに該当する時間は13時間、PMに該当する時間は11時間になってしまうので、それはそれで微妙かも知れない)
# 定型フォーマット
実際には定型的なフォーマットはtime/format.go (opens new window)に定義されているので、極力、こちらを使うほうがミスがなくてわかりやすいような気がする。
const (
Layout = "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order.
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"
)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
例えばデータベースへの保存、取得であれば自分でフォーマットを書くよりも、下記のように機会的に RFC3339
に変換するのがよさそうである。
t := time.Now()
fmt.Println(string(t.Format(time.RFC3339)),"\n") // 2022-01-05T15:42:15+09:00
2
# フォーマット文字列をtime.Time変数に変換する
Go言語では文字列を日付として読み込むにはtime.Parse
関数を使う。
t, err := time.Parse("2006-01-02 15:04:05", "2022-01-05 15:42:15")
if err != nil {
panic(err)
}
fmt.Println(t) // 2022-01-05 15:42:15 +0000 UTC
2
3
4
5
実際にはすでに説明したように、RFC3339など主要な日付フォーマットはtimeパッケージ内に定義されているので、それをそのまま使うのがよいと思う。
t, err := time.Parse(time.RFC3339, "2022-01-05T15:42:15+09:00")
if err != nil {
panic(err)
}
fmt.Println(t) // 2022-01-05 15:42:15 +0900 JST
2
3
4
5
time.Parse
は末尾にスペースが入っていたり日付の桁数が少しでも違ったりするとうまくいかないので、実際には自分でフォーマットの指定は一切行わずにすべて定数のみを使うほうが安全な気がする。
# おまけ: Golangで自由にフォーマットする
time.Parse
は個人的にあまり使いやすくはないので、自前で日付処理用のライブラリを作成した。
go-timeparser (opens new window)
import "github.com/kaz-yamam0t0/go-timeparser/timeparser"
// tdata, _ := Now()
// tdata, _ := New("2022-01-31 11:22:33.123456789")
// tdata, _ := NewAsUTC("2022-01-31 11:22:33.123456789")
tdata, _ := NewAsUTC("31st Jan 2022 11:22:33.123456789")
//
// If you want to adjust the timezone offset difference from your local env,
// first create a variable with `New()` and then convert it to UTC with `SetUTC()`
//
// tdata, _ := New("2022-01-31 11:22:33.123456789")
// tdata.SetUTC()
fmt.Println(tdata.GetYear()) // 2022
fmt.Println(tdata.GetMonth()) // 1
fmt.Println(tdata.GetDay()) // 31
fmt.Println(tdata.GetHour()) // 11
fmt.Println(tdata.GetMinute()) // 22
fmt.Println(tdata.GetSecond()) // 33
fmt.Println(tdata.GetMillisecond()) // 123
fmt.Println(tdata.GetMicrosecond()) // 123456
fmt.Println(tdata.GetNanosecond()) // 123456789
//
// Format
//
fmt.Println(tdata.String()) // 2022-01-31T11:22:33+00:00
fmt.Println(tdata.Format("l jS \\of F Y h:i:s A")) // Monday 31st of January 2022 06:22:33 PM
//
// Setter methods
//
tdata.SetYear(2022)
tdata.SetMonth(1)
tdata.SetDay(31)
tdata.SetHour(11)
tdata.SetMinute(22)
tdata.SetSecond(33)
//
// Difference
//
tm, _ := NewAsUTC("2020-12-31 11:22:33.123456789")
fmt.Println(tdata.DiffYears(tm)) // 1
fmt.Println(tdata.DiffMonths(tm)) // 13
fmt.Println(tdata.DiffDays(tm)) // 396
fmt.Println(tdata.DiffHours(tm)) // 9504
fmt.Println(tdata.DiffMinutes(tm)) // 570240
fmt.Println(tdata.DiffSeconds(tm)) // 34214400
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51