日付の生成、加算・減算、比較、フォーマットなどの操作は、プログラミングでよくある操作の1つです。
データベースやAPIなどで外部と日付データを送受信する際には、決まったフォーマットにする必要があります。
そのため、プログラミング初心者にとって、日付操作は学習すべき事項の1つとなります。
本記事では、Goでよく使われる日付操作について解説します。
プログラミング初心者の方の学習や、忘れてしまった方の復習として、参考にしていただければ幸いです。
記載しているプログラムは、Go1.15.2を使って動作確認をしています。
Goの日付操作
よくある日付操作として、以下の内容を採り上げます。
- 日付を扱うパッケージ
- 日時の生成
- 日時・曜日の取得
- 日時の加算・減算
- 日時の差分
- 日時の比較
- 日時から文字列へのフォーマット
- 文字列から日時への変換
日付を扱うパッケージ
Goで日付を扱うには、timeパッケージを使用します。
timeパッケージを使用するには、importに “time” を指定します。
日時の生成
日時を生成するには、大きく2つの方法があります。
現在時刻で生成する方法
t := time.Now() fmt.Println(t) // -> 2020-10-23 09:09:30.400977571 +0900 JST m=+0.000208618
任意の日時を指定して生成する方法
t = time.Date(2020, 10, 23, 9, 1, 2, 3, time.Local) fmt.Println(t) // -> 2020-10-23 09:01:02.000000003 +0900 JST
日時・曜日の取得
日時の各属性値を取得する方法
日時の各関数を呼出すことで取得することができます。
t = time.Date(2020, 10, 23, 9, 1, 2, 3, time.Local) fmt.Println(t.Year()) // -> 2020 fmt.Println(t.Month()) // -> October fmt.Println(int(t.Month())) // -> 10 fmt.Println(t.Day()) // -> 23 fmt.Println(t.Hour()) // -> 9 fmt.Println(t.Minute()) // -> 1 fmt.Println(t.Second()) // -> 2 fmt.Println(t.Nanosecond()) // -> 3 fmt.Println(t.YearDay()) // -> 297 fmt.Println(t.Zone()) // -> JST 32400 fmt.Println(t.Date()) // -> 2020 October 23 fmt.Println(t.Clock()) // -> 9 1 2
Monthはそのまま取得すると文字列表記となってしまうため、数値で取得するにはキャストする必要があります。
YearDayは、1月1日を1とした通算日を取得します。
Zoneはタイムゾーンの情報を取得します。
Dateは年月日を3つの戻り値で返します。
Clockは時分秒を3つの戻り値で返します。
曜日を取得する方法
曜日の取得は、Weekday関数を使います。
結果は文字列表記で取得されるため、数値で取得するにはキャストする必要があります。
数値は以下の意味となります。
t = time.Date(2020, 10, 23, 9, 1, 2, 3, time.Local) // 2020/10/23は金曜日 fmt.Println(t.Weekday()) // -> Friday fmt.Println(int(t.Weekday())) // -> 5
日時の加算・減算
日時の加算や減算を行うには、年月日を加算・減算する方法と時刻を加算・減算する方法があります。
年月日の加算・減算
t = time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local) // 1年2ヶ月3日後 fmt.Println(t.AddDate(1, 2, 3)) // -> 2021-03-04 00:00:00 +0900 JST // 1年2ヶ月3日前 fmt.Println(t.AddDate(-1, -2, -3)) // -> 2018-10-29 00:00:00 +0900 JST
時刻の加算・減算
t = time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local) // 1秒後 fmt.Println(t.Add(1 * time.Second)) // -> 2020-01-01 00:00:01 +0900 JST // 2分後 fmt.Println(t.Add(2 * time.Minute)) // -> 2020-01-01 00:02:00 +0900 JST // 3時間前 fmt.Println(t.Add(-3 * time.Hour)) // -> 2019-12-31 21:00:00 +0900 JST
日時の差分
日時の差分を取得するには、Sub関数を使います。差分はナノ秒(int64)で取得されます。
t1 := time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local) t2 := time.Date(2020, 10, 23, 9, 1, 2, 3, time.Local) fmt.Println(t2.Sub(t1)) // -> 7113h1m2.000000003s fmt.Println(int(t2.Sub(t1))) // -> 25606862000000003
日時の比較
日時の前後を比較にするには、Before関数/After関数/Equal関数を使います。
t1 = time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local) t2 = time.Date(2020, 10, 23, 9, 1, 2, 3, time.Local) fmt.Println(t1.Before(t2)) // -> true fmt.Println(t1.Equal(t2)) // -> false fmt.Println(t1.After(t2)) // -> false
日時から文字列へのフォーマット
日時から文字列へ変換してフォーマットするには、Format関数を使います。
フォーマットは、RFC3339などの予め定義されている形式と、書式を指定する形式があります。
書式を指定する場合は、アメリカ形式の1月2日午後3時4分5秒2006年の各数値を並び替えて書式を作ります。時間に15を指定すると24時間形式になります。
t = time.Date(2020, 10, 23, 9, 1, 2, 3, time.Local) fmt.Println(t.Format(time.RFC3339)) // -> 2020-10-23T09:01:02+09:00 fmt.Println(t.Format("2006/01/02")) // -> 2020/10/23 fmt.Println(t.Format("2006/01/02 03:04:05")) // -> 2020/10/23 09:01:02 fmt.Println(t.Format("2006年01月02日 15時04分05秒")) // -> 2020年10月23日 09時01分02秒
Format関数に指定できる書式の詳細はリファレンスマニュアルをご覧ください。
文字列から日時への変換
文字列から日時へ変換するには、Parse関数を使います。
第1引数にフォーマット、第2引数に日時したい文字列を指定します。
タイムゾーンを指定しない場合はUTCで変換されます。
t, _ = time.Parse("2006/01/02 03:04:05", "2020/10/23 09:01:02") fmt.Println(t) // -> 2020-10-23 09:01:02 +0000 UTC fmt.Println(t.Local()) // -> 2020-10-23 18:01:02 +0900 JST t, _ = time.Parse("2006/01/02 03:04:05 MST", "2020/10/23 09:01:02 JST") fmt.Println(t) // -> 2020-10-23 09:01:02 +0900 JST
日付操作には十分なテストが必要
日付と文字列を変換していると、環境によって時間が変わってしまうことがあります。
また、クライアントとサーバで日時をやり取りすると時間がが変わってしまうなどもあります。
こうした環境による時間の変化は、タイムゾーンが原因であることが考えられます。
実際のプロジェクトでは、データベースはどのタイムゾーンなのか、サーバはどのタイムゾーンで設定するのか、クライアントはどのタイムゾーンで表示するのかといったことを最初に決めておく必要があります。
これらを統一しておかないと、意図せず異なった日時で保存されてしまったり、間違った時間を元に処理が動いてしまったりといったことが発生します。
また、うるう年やうるう秒など、特定の時にだけ発生する時間差などもあります。
過去にもこうした対策がきちんと行われていないことが原因で、大きなトラブルになった事例もあります。
日付を扱う際には、実装時にも注意し、テストを十分に行うことをおすすめします。
今回はGoの日付操作について紹介しました。
参考になれば幸いです。
コメント