GolangのJSON変換で任意の日付形式を変換する
Golangのjson.Marshalやjson.Unmarshalは特定の形式の日付形式しか変換できません。
具体的に言うと、RFC3339形式で、2006-01-02T15:04:05Z07:00って感じのやつです。
日本だと 2006/01/02 って形式が多い気がしますし、 2006-01-02 とか 20060102 ってことも多いと思います。
これらのjson.Unmarshalでパース出来ないのはめんどくさいなーってことで、その辺を解決してみます。
ただ、なんか冗長ですし、めんどくさいです。
独自のtime.Time型を用意する
time.TimeのMarshalJsonやUnmarshalJsonが決め打ちでRFC3339になっているのが根本的な問題です。
これだけ回避できれば解決できるので、独自のtime.Time型を用意して、MarshalJsonやUnmarshalJsonをoverriceしてしまいます。
code:golang
type MyTime struct {
time.Time
}
独自のtime.Time型はこれだけです。
あとは好きなMarshalJsonとUnmarshalJsonをくっつけるだけです。
独自のパーサーを用意する
まずは簡単な構造体からjson形式に変換するMarshalからです。
今回はtime.Timeから 20060102 の形式にします。YYYYMMDDの形ですね。
code:golang
func (t MyTime) MarshalJSON() ([]byte, error) {
return []byte(" + t.Time.Format("20060102") + "), nil
}
これだけです。
time.TimeのFormatを使って任意の形の文字列にし、それをjsonで返すためにダブルクォートをくっつけてます。
次に難しいほうのjsonから構造体に変換するUnmarshalです。
20060102 の形式から構造体にします。
code:golang
func (t *MyTime) UnmarshalJSON(data []byte) error {
// Ignore null, like in the main JSON package.
if string(data) == "null" {
return nil
}
// Fractional seconds are handled implicitly by Parse.
timeTime, err := time.ParseInLocation("20060102", string(data), time.Local)
if err != nil {
return err
}
*t = MyTime{timeTime}
return err
}
難しい方と言っても、こちらもやってることは単純です。
nullの場合は何もせずに抜ける
time.ParseInLocationで任意のフォーマットでパースして、自分自身の構造体を更新する。
ということをやってます。
これで両方向に変換できるようになりました。
おわりに
よくよく考えれば、time.Timeに限らずMarshal、Unmarshalを独自の構造体に行なう場合、同様の作り方をすることになると思います。
ダックタイピングが活用されているなーと感じつつも、ぱっとこの方法が浮かばない私はまだGo言語初心者ですね……。
参考
最終更新日 : 2019/09/10