在Golang中解组错误格式化的日期时间

Joa*_*kim 7 datetime json iso8601 go rfc3339

背景

我正在学习Go,我正在尝试对日期时间进行一些JSON解组.

我有一些由我在C中编写的程序生成的JSON,我输出的是我认为有效的ISO8601/RFC3339时区偏移量.我正在使用strftime以下格式字符串:

%Y-%m-%dT%H:%M:%S.%f%z
Run Code Online (Sandbox Code Playgroud)

(注意,本机%f不支持strftime,我有一个用纳秒替换它的包装器).

这将产生以下结果:

2016-08-08T21:35:14.052975+0200
Run Code Online (Sandbox Code Playgroud)

然而,在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)
}
Run Code Online (Sandbox Code Playgroud)

输出:

panic: parsing time "2016-08-08T21:35:14.052975+0200" as "2006-01-02T15:04:05.999999999Z07:00": cannot parse "+0200" as "Z07:00"
Run Code Online (Sandbox Code Playgroud)

(工作示例:https://play.golang.org/p/5xcM0aHsSw)

这是因为RFC3339期望时区偏移量02:00采用a 格式:,但strftime输出为0200.

所以我需要在我的C程序中修复它以输出正确的格式.

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

但是,现在我有一堆JSON文件格式不正确:

2016-08-08T21:35:14.052975+0200
Run Code Online (Sandbox Code Playgroud)

而不是正确的(与:时区偏移):

2016-08-08T21:35:14.052975+02:00
Run Code Online (Sandbox Code Playgroud)

但我仍然希望能够在我的Go程序中正确解组它.优选地,仅具有此差异的两个不同JSON文件应以完全相同的方式解析.

关于封送回JSON,应该使用正确的格式.

这是我在我的定义中的方式struct:

Time            time.Time `json:"time"`
Run Code Online (Sandbox Code Playgroud)

所以问题是,这样做的"Go"方式是什么?

另外在我使用的代码示例中RFC3339Nano.我如何在结构的元数据中指定它?正如我现在json:"time"所说的那样只会忽略纳秒秒?

Cra*_*row 15

您可以定义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"`
}
Run Code Online (Sandbox Code Playgroud)

Try on Go Playground

在上面的示例中,我们采用预定义格式time.RFC3339Nano,其定义如下:

RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
Run Code Online (Sandbox Code Playgroud)

并删除 :

"2006-01-02T15:04:05.999999999Z0700"
Run Code Online (Sandbox Code Playgroud)

这里使用的时间格式time.Parse如下所述:https: //golang.org/pkg/time/#pkg-constants

另请参阅https://golang.org/pkg/time/#Parse的文档time.Parse

PS年份2006用于时间格式字符串的事实可能是因为当年发布了第一版Golang.