Goの日付操作【プログラミング初心者向け教材】

プログラミング

日付の生成、加算・減算、比較、フォーマットなどの操作は、プログラミングでよくある操作の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関数を使います。
結果は文字列表記で取得されるため、数値で取得するにはキャストする必要があります。
数値は以下の意味となります。

0:日曜日、1:月曜日、2:火曜日、3:水曜日、4:木曜日、5:金曜日、6:土曜日
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の日付操作について紹介しました。

参考になれば幸いです。

コメント

タイトルとURLをコピーしました