dongmi1221 2016-08-27 10:09
浏览 82
已采纳

在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?

  • 写回答

2条回答 默认 最新

  • dousi4950 2016-08-27 10:44
    关注

    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"`
    }
    

    <kbd>Try on Go Playground</kbd>

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮