はじめに
Go で、文字列から日時へパースする際にタイムゾーンの指定で困ったので調べました。
結論から先に述べると、time.Parseはデフォルトで UTC を設定されます。
基本的にはロケーションが設定できるtime.ParseInLocationを利用するのが妥当だろうという見解に至りました。
注意:本記事に記載しているコードはエラー処理を無視しています。実際に利用する場合はちゃんとエラー処理しましょう。
time.Parseはデフォルトで UTC になる
パースする文字列が2018-01-01 00:00:00のように、タイムインジケータを指定していない場合は UTC として解釈されます。
日本時間にするには、2018-01-01 00:00:00 (JST)のようにタイムインジケータを指定する必要があります。
// タイムインジケータがないのでUTCと解釈される
// => 2018-01-01 00:00:00 +0000 UTC
t, _ := time.Parse("2006-01-02 15:04:05", "2018-01-01 00:00:00")タイムゾーンを指定する方法
方法は下記の 2 種類あります。
1. time.Parseでタイムインジケータを含めてパースする
パース時のフォーマットにタイムインジケータを含ませることで指定できます。
// タイムインジケータを指定すると、そのタイムゾーンで解釈される
// タイムインジケータを認識させたい場合はformatに含める
// => 2018-01-01 00:00:00 +0900 JST
t2, _ := time.Parse("2006-01-02 15:04:05 (MST)", "2018-01-01 00:00:00 (JST)")2. time.ParseInLocationでロケーションを指定する
ロケーションを指定してパースするtime.ParseInLocationを使用することで、2018-01-01 00:00:00のようなタイムインジケータのない文字列もパースできるようになります。
// 第3引数でtime.Locationを指定することで、タイムインジケータなしでタイムゾーンを指定できる
// => 2018-01-01 00:00:00 +0900 JST
jst, _ := time.LoadLocation("Asia/Tokyo")
t1, _ := time.ParseInLocation("2006-01-02 15:04:05", "2018-01-01 00:00:00", jst)
// 第3引数でロケーションを指定し、かつ文字列内でタイムインジケータが指定されている場合は、
// タイムインジケータの設定が有効になる
// => 2018-01-01 00:00:00 +0000 UTC
t2, _ := time.ParseInLocation("2006-01-02 15:04:05 (MST)", "2018-01-01 00:00:00 (UTC)", jst)time.Parseとtime.ParseInLocationについて
2 つのメソッドの仕様をまとめます。
time.Parse- 文字列にタイムインジケータが指定されていない場合は、UTC になる
- 文字列でタイムインジケータが指定されている場合は、指定したタイムゾーンになる
time.ParseInLocation- 文字列でタイムインジケータが指定されていない場合は、第 3 引数で指定されたタイムゾーンになる
- 文字列でタイムインジケータが指定されている場合は、指定したタイムゾーンになる
付録
挙動チェック用コード
package main
import (
"fmt"
"time"
)
func main() {
jst, _ := time.LoadLocation("Asia/Tokyo")
a, _ := time.Parse("2006-01-02 15:04:05", "2018-01-01 00:00:00")
b, _ := time.Parse("2006-01-02 15:04:05 (MST)", "2018-01-01 00:00:00 (JST)")
c, _ := time.ParseInLocation("2006-01-02 15:04:05", "2018-01-01 00:00:00", jst)
d, _ := time.ParseInLocation("2006-01-02 15:04:05 (MST)", "2018-01-01 00:00:00 (UTC)", jst)
fmt.Println("a: ", a)
fmt.Println("b: ", b)
fmt.Println("c: ", c)
fmt.Println("d: ", d)
}実行結果
a: 2018-01-01 00:00:00 +0000 UTC
b: 2018-01-01 00:00:00 +0900 JST
c: 2018-01-01 00:00:00 +0900 JST
d: 2018-01-01 00:00:00 +0000 UTCおわりに
time.Parseでも期待する処理は実装できますが、パースしたい文字列にタイムインジケータがついている場合はおそらくそれほど多くありません。time.ParseInLocationを使用しておくほうがより問題は起きづらいでしょう。