web-dev-qa-db-ja.com

誤ってフォーマットされた日時のアンマーシャル

バックグラウンド

私はGoを学んでいて、日時のJSONアンマーシャリングを実行しようとしています。

Cで作成したプログラムによって生成されたJSONがあり、有効だと思ったものを出力しています ISO8601 / RFC3339 タイムゾーンオフセット。次の形式の文字列で strftime を使用しています。

%Y-%m-%dT%H:%M:%S.%f%z

%fstrftime でサポートされていないことに注意してください。ネイティブでは、ナノ秒に置き換えるラッパーがあります)。

これにより、次の結果が生成されます。

2016-08-08T21:35:14.052975+0200

ただし、Goでこれをアンマーシャリングしても機能しません: https://play.golang.org/p/vzOXbzAwdW

package main

import (
    "fmt"
    "time"
)

func main() {
    t, err := time.Parse(time.RFC3339Nano, "2016-08-08T21:35:14.052975+0200")
    if err != nil {
        panic(err)
    }
    fmt.Println(t)
}

出力:

panic: parsing time "2016-08-08T21:35:14.052975+0200" as "2006-01-02T15:04:05.999999999Z07:00": cannot parse "+0200" as "Z07:00"

(実例: https://play.golang.org/p/5xcM0aHsSw

これは、 RFC3339は、タイムゾーンオフセットが02:00: の形式であると想定しているためですが、 strftime は次のように出力します。 0200

したがって、正しい形式を出力するには、Cプログラムでこれを修正する必要があります。

 %z     The +hhmm or -hhmm numeric timezone (that is, the hour and
              minute offset from UTC). (SU)

質問

ただし、現在、この誤った形式のJSONファイルがたくさんあります。

2016-08-08T21:35:14.052975+0200

正しい代わりに(タイムゾーンオフセットに:を使用):

2016-08-08T21:35:14.052975+02:00

それでも、Goプログラムで正しくアンマーシャリングできるようにしたいです。できれば、この違いだけを持つ2つの異なるJSONファイルをまったく同じ方法で解析する必要があります。

JSONへのマーシャリングに関しては、正しい形式を使用する必要があります。

これが私のstructで定義した方法です。

Time            time.Time `json:"time"`

だから問題は、これを行う「Go」の方法は何ですか?

また、私のコード例では、RFC3339Nanoを使用しています。構造体のメタデータでもそれをどのように指定しますか? json:"time"だけで今持っているので、ナノ秒は無視されますか?

10
Joakim

両方の形式をサポートする独自のtimeフィールドタイプを定義できます。

type MyTime struct {
    time.Time
}

func (self *MyTime) UnmarshalJSON(b []byte) (err error) {
    s := string(b)

    // Get rid of the quotes "" around the value.
    // A second option would be to include them
    // in the date format string instead, like so below: 
    //   time.Parse(`"`+time.RFC3339Nano+`"`, s) 
    s = s[1:len(s)-1]

    t, err := time.Parse(time.RFC3339Nano, s)
    if err != nil {
        t, err = time.Parse("2006-01-02T15:04:05.999999999Z0700", s)
    }
    self.Time = t
    return
}

type Test struct {
    Time MyTime `json:"time"`
}

Try on Go Playground

上記の例では、次のように定義された事前定義された形式time.RFC3339Nanoを使用します。

RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"

:を削除します

"2006-01-02T15:04:05.999999999Z0700"

time.Parseで使用されるこの時間形式については、次のように説明します。 https://golang.org/pkg/time/#pkg-constants

time.Parsehttps://golang.org/pkg/time/#Parse のドキュメントも参照してください。

P.S.年2006が時間形式の文字列で使用されているのは、おそらくその年にGolangの最初のバージョンがリリースされたためです。

17
CrazyCrow