Go 如何从json解析非标准时间格式

Go 如何从json解析非标准时间格式,go,time,Go,Time,假设我有以下json { name: "John", birth_date: "1996-10-07" } 我想把它解码成以下结构 type Person struct { Name string `json:"name"` BirthDate time.Time `json:"birth_date"` } 像这样 person := Person{} decoder := json.NewDecoder(req.Body); if err := deco

假设我有以下json

{
    name: "John",
    birth_date: "1996-10-07"
}
我想把它解码成以下结构

type Person struct {
    Name string `json:"name"`
    BirthDate time.Time `json:"birth_date"`
}
像这样

person := Person{}

decoder := json.NewDecoder(req.Body);

if err := decoder.Decode(&person); err != nil {
    log.Println(err)
}
t, err := time.Parse("2006-01-02", "1996-10-07")
这给了我错误
将时间“1996-10-07”解析为“2006-01-02T15:04:05Z07:00”:无法将“”解析为“T”

如果我手动解析它,我会这样做

t, err := time.Parse("2006-01-02", "1996-10-07")

但是,当时间值来自json字符串时,如何让解码器以上述格式解析它?

当您需要实现自定义封送和解封送功能时,就是这种情况

UnmarshalJSON(b []byte) error { ... }

MarshalJSON() ([]byte, error) { ... }
按照Golang文档中的示例,您可以得到如下结果:

// First create a type alias
type JsonBirthDate time.Time

// Add that to your struct
type Person struct {
    Name string `json:"name"`
    BirthDate JsonBirthDate `json:"birth_date"`
}

// Implement Marshaler and Unmarshaler interface
func (j *JsonBirthDate) UnmarshalJSON(b []byte) error {
    s := strings.Trim(string(b), "\"")
    t, err := time.Parse("2006-01-02", s)
    if err != nil {
        return err
    }
    *j = JsonBirthDate(t)
    return nil
}
    
func (j JsonBirthDate) MarshalJSON() ([]byte, error) {
    return json.Marshal(j)
}

// Maybe a Format function for printing your date
func (j JsonBirthDate) Format(s string) string {
    t := time.Time(j)
    return t.Format(s)
}

如果有很多struct,而您只是实现自定义封送和解封送函数,那么这需要做很多工作。您可以使用另一个库,例如json迭代器扩展:


我编写了一个包来处理日期为的
yyyy-MM-dd
yyy-MM-ddThh:MM:ss

它使用上面答案中的类型别名方法,然后通过一些修改实现
MarshalJSON
UnmarshalJSON
函数

// MarshalJSON outputs JSON.
func (d YYYYMMDD) MarshalJSON() ([]byte, error) {
    return []byte("\"" + time.Time(d).Format(formatStringYYYYMMDD) + "\""), nil
}

// UnmarshalJSON handles incoming JSON.
func (d *YYYYMMDD) UnmarshalJSON(b []byte) (err error) {
    if err = checkJSONYYYYMMDD(string(b)); err != nil {
        return
    }
    t, err := time.ParseInLocation(parseJSONYYYYMMDD, string(b), time.UTC)
    if err != nil {
        return
    }
    *d = YYYYMMDD(t)
    return
}
在正确的时区进行解析很重要。我的代码假定UTC,但出于某种原因,您可能希望使用计算机的时区

我还发现,使用
time.Parse
函数的解决方案将Go的内部机制泄漏为一条错误消息,客户端认为这条消息没有帮助,例如:
无法将“sdfdf-01-01”解析为“2006”“
。只有当您知道服务器是用Go编写的,并且
2006
是示例日期格式时,这才有用,因此我添加了更可读的错误消息


我还实现了
Stringer
接口,这样它就可以在日志或调试消息中很好地打印出来。

可能重复的权限,对于
UnmarshalJSON
func,OP可以添加多个
时间。根据需要支持的不同格式,解析
尝试。我相信
时间的格式。RFC3339
是默认的解析器,在Sure中可以找到更多格式,当您有自定义的un/MASHALL函数时,您应该尝试覆盖所有可能的情况。在
*j=JB(t)
行中的JB是什么?因为您有一个类型别名,所以需要强制转换它。阅读本文以及文档的相应链接:
MarshalJSON()
方法会导致堆栈溢出死机,因为它会间接调用自身。