💡
Goとフロントエンドでのタイムゾーンを考慮した日付の扱い方
タイムゾーン周りがややこしいので調べた内容をまとめてみます。
ざっくりまとめると、
- フロント←→バックエンドのAPIインターフェースは
ISO8601/RFC3339
フォーマットにする - バックエンドではタイムゾーンはUTCで扱う
が良いのかなと思いました。
実用Go言語
にあるように、time.RFC3339Nano
を使うとフロント側でもバックエンド側でも扱いやすくなります。
どれを使うかは悩みどころですが、JavaScriptとのデータ交換を考えると、time.RFC3339Nanoを使うのが良いでしょう。ナノ秒までの情報を含んだ文字列が作成できます。このフォーマット文字列で出力された日時の情報は、JavaScriptのDateコンストラクタやDate.parse()関数で処理できます。逆にJavaScriptのDateインスタンスのtoISOString()で生成した文字列は、time.RFC3339Nanoを指定したtime.Parse()でパースできます。Goのサーバーから返した日時の情報を、フロントエンドでも問題なく利用できます。
もう少し細かくみていくと、こんな流れになります
- ユーザー入力:
2022-08-18 14:58:00
- フロントエンドでの解釈:
Dateオブジェクト(Thu Aug 18 2022 14:58:00 GMT+0900 (Japan Standard Time))
- フロントエンド→API呼び出し:
2022-08-18T05:58:00.000Z
- API→データベース:指定方法はデータベースやライブラリによる。データベースはUTCで扱う
この流れであれば、タイムゾーンは特に意識しなくて良いはずです。
表示に関しては、jsがローカルタイムゾーンを見てよしなにやってくれるはず。(だと思うのですが、これだけで問題ないのか若干不安になってきました)
バックエンドでもメッセージ表示だったりメール送信だったりと、気にするケースはあります。
フロント側、バックエンド側の変換処理
フロント側 js
> var date = new Date("2022-08-18 14:58:00") // 入力値
Thu Aug 18 2022 14:58:00 GMT+0900 (Japan Standard Time)
> date.toISOString() // APIに渡す場合。ISOStringでフォーマットする
'2022-08-18T05:58:00.000Z'
> new Date('2022-08-18T05:58:00Z') // APIから受け取った場合。そのままDateコンストラクタで生成する
Thu Aug 18 2022 14:58:00 GMT+0900 (Japan Standard Time)
バックエンド側 Go
// フロントから渡された値をParse
t, e := time.Parse(time.RFC3339Nano, `2022-08-18T05:58:00.000Z`)
// フロントに返す用にフォーマット
formatted := t.Format(time.RFC3339Nano)
fmt.Println(formatted) // => 2022-08-18T05:58:00Z
参考
Discussion