💡

Goとフロントエンドでのタイムゾーンを考慮した日付の扱い方

2022/08/18に公開

タイムゾーン周りがややこしいので調べた内容をまとめてみます。

ざっくりまとめると、

  1. フロント←→バックエンドのAPIインターフェースはISO8601/RFC3339フォーマットにする
  2. バックエンドではタイムゾーンはUTCで扱う

が良いのかなと思いました。

実用Go言語 にあるように、time.RFC3339Nanoを使うとフロント側でもバックエンド側でも扱いやすくなります。

どれを使うかは悩みどころですが、JavaScriptとのデータ交換を考えると、time.RFC3339Nanoを使うのが良いでしょう。ナノ秒までの情報を含んだ文字列が作成できます。このフォーマット文字列で出力された日時の情報は、JavaScriptのDateコンストラクタやDate.parse()関数で処理できます。逆にJavaScriptのDateインスタンスのtoISOString()で生成した文字列は、time.RFC3339Nanoを指定したtime.Parse()でパースできます。Goのサーバーから返した日時の情報を、フロントエンドでも問題なく利用できます。

https://www.oreilly.co.jp/books/9784873119694/

もう少し細かくみていくと、こんな流れになります

  1. ユーザー入力:2022-08-18 14:58:00
  2. フロントエンドでの解釈:Dateオブジェクト(Thu Aug 18 2022 14:58:00 GMT+0900 (Japan Standard Time))
  3. フロントエンド→API呼び出し:2022-08-18T05:58:00.000Z
  4. 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

参考

https://www.m3tech.blog/entry/timezone-handling

https://blog.studysapuri.jp/entry/2016/12/05/090000

Discussion