解组日期格式不正确的日期 [英] Unmarshal incorrectly formatted datetime

查看:552
本文介绍了解组日期格式不正确的日期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

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

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

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

(请注意, strftime 本机,我有一个包装器,将其替换为十亿分之一秒.

这将产生以下结果:

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程序中正确解组它.最好两个具有此区别的不同JSON文件应该以完全相同的方式进行解析.

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

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

Time            time.Time `json:"time"`

问题是,执行此操作的执行"方式是什么?

在我的代码示例中,我也在使用RFC3339Nano.我还要如何在结构的元数据中指定它?就像我现在只用json:"time"一样,它会忽略纳秒吗?

解决方案

您可以定义自己的支持两种格式的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"`
}
 

在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.Parse的文档 https://golang.org/pkg/time/#Parse

P.S.在时间格式字符串中使用年份2006的事实可能是因为该年发布了Golang的第一个版本.

Background

I am learning Go and I'm trying to do some JSON unmarshaling of a datetime.

I have some JSON produced by a program I wrote in C, I am outputting what I thought was a valid ISO8601 / RFC3339 timezone offset. I'm using strftime with the following format string:

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

(Note that %f is not supported by strftime natively, I have a wrapper that replaces it with the nanoseconds).

This will then produce the following result:

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

Unmarshaling this in Go however will not work: 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)
}

Output:

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

(Working example: https://play.golang.org/p/5xcM0aHsSw)

This is because RFC3339 expects the timezone offset to be in the format 02:00 with a :, but strftime outputs it as 0200.

So I need to fix this in my C program to output the correct format.

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

Question

However, now I have a bunch of JSON files with this incorrect format:

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

instead of the correct (with the : in the timezone offset):

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

but I still want to be able to unmarshal it correctly in my Go program. Preferably two different JSON files with only this difference should parse in the exact same way.

Regarding marshaling back to JSON, the correct format should be used.

This is how I have defined it in my struct:

Time            time.Time `json:"time"`

So the question is, what is the "Go" way of doing this?

Also in my code example I am using RFC3339Nano. How would I specify that in the metadata for the struct as well? As I have it now with just json:"time" will that ignore the nano seconds?

解决方案

You can define your own time field type that supports both formats:

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

In the example above we take the predefined format time.RFC3339Nano, which is defined like this:

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

and remove the :

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

This time format used by time.Parse is described here: https://golang.org/pkg/time/#pkg-constants

Also see the documentation for time.Parse https://golang.org/pkg/time/#Parse

P.S. The fact that the year 2006 is used in the time format strings is probably because the first version of Golang was released that year.

这篇关于解组日期格式不正确的日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆