golang time Unmarshal 必须包含时区吗?

不包含时区貌似不会成功呢

阅读 5.5k
2 个回答

楼上的回答说的很对,不知道题主问题解决了没有。我也测试了一下,随便把一些过程写在这里。

首先,要支持 JSON 的编解码,就必须要实现两个接口,分别是 json.Marshaler(组包) 和 json.Unmashaler(解包)。

两个接口的定义如下:

type Marshaler interface {
    MarshalJSON() ([]byte, error)
}

type Unmarshaler interface {
    UnmarshalJSON([]byte) error
}

第一种方案,为什么必须是 RFC 3339 格式。

time.Time 已经实现了这两个接口,可以进入到 time/time.go 找到源码实现。而之所以字段必须是 RFC 3999,因为 time.Time 实现的 UnmarshalJSON 方法就是按这个格式解析的。

time.Time 的 UnmarshalJSON 的源码实现如下:

func (t *Time) UnmarshalJSON(data []byte) error {
    // Ignore null, like in the main JSON package.
    if string(data) == "null" {
        return nil
    }
    // Fractional seconds are handled implicitly by Parse.
    var err error
    *t, err = Parse(`"`+RFC3339+`"`, string(data))
    return err
}

非常简单。

关于什么是 RFC 3999 格式,题主可以参考这篇文章,互联网上的日期和时间

假设,现在需要一个支持自定义格式的时间类型,Go 还是非常灵活的,基于 time.Time 重新定义即可,在这个基础上再实现 json.Unmarshaler 接口。

type CTime time.Time
// UnmarshalJSON is joson.Unmarshaler
func (ct *CustomTime) UnmarshalJSON(data []byte) error {
    // Ignore null, like in the main JSON package.
    if string(data) == "null" {
        return nil
    }
    // Fractional seconds are handled implicitly by Parse.
    var err error
    t, _ := time.ParseInLocation(`"2006-01-02T15:04:05"`, string(data), time.Local)
    *ct = CustomTime(t)
    return err
}

和之前的 time.Time 实现基本一样,只是解析的格式不一样了。这里就可以不包含时区了,因为已经固定时区为 time.Local,即按当前时区解析。

如果想做的更灵活点,可以用 for range 把每个时间格式测试一下,通过判断 Parse 返回的 err 确定是否解析成功。当然,这种方法不推荐。

这种方式的缺点是 fmt.Printf 打印的时候,时间不够直观,打印的底层的数据,可以自己试下就知道。当然,这应该是可以解决的。

还有另外一种方式,定义一个新的时间类型结构体,里面只有一个 time.Time 类型成员。

type CustomTime struct {
    Time time.Time
}

func (ct *CustomTime) UnmarshalJSON(data []byte) error {
    // Ignore null, like in the main JSON package.
    if string(data) == "null" {
        return nil
    }
    // Fractional seconds are handled implicitly by Parse.
    var err error
    ct.Time, err = time.ParseInLocation(`"2006-01-02T15:04:05"`, string(data), time.Local)
    return err
}

代码都差不多。这种方式再使用 fmt.Printf 打印,效果就好了很多。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏