Go json 时间格式解析

默认RFC 3339

在Go中,解析json的时间格式默认是RFC 3339,一般情况下 struct 转 json,或 json 转回 struct都没有问题。

type Data struct {
	Name    string    `json:"name"`
	Started time.Time `json:"started"`
}

var jsonStr = []byte(`
{
  "name": "new year",
  "started": "2021-01-01T00:00:00.000+08:00"
}`)

func main() {
	var data Data
	if err := json.Unmarshal(jsonStr, &data); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%+v\n", data)
}

Z,T

上述代码中,日期和时间使用T分隔开,其实 RFC 3339规范中允许使用空格分隔,目前Go的time包还是使用T分隔。

+8:00则表示时区,如果不想使用时区,可以使用Z代替:2021-01-01T00:00:00.000Z

还有一点需要注意的是,在Go中,RFC 3339的定义是:

RFC3339     = "2006-01-02T15:04:05Z07:00"

但是如果这样写,却不行。

t, err := time.Parse(time.RFC3339, time.RFC3339)
if err != nil {
	log.Fatal(err)
}
fmt.Println(t)

会报错:”parsing time “2006-01-02T15:04:05Z07:00”: extra text: 07:00”。

但是如果是把上述json的时间值修改成2021-01-01T00:00:00.000Z就没有问题。

格式

默认的时间格式是RFC 3339,如果想换成其他格式,需要自己实现。

先看一下时间格式的定义

一般情况下格式化时间可以这样做:

t, err := time.Parse("2006-01-02", "2021-01-01")

但是如果想从json中解析成不同格式,需要自己实现json.Unmarshaler接口。

type MyTime struct {
	time.Time
}

const layout = "2006-01-02"

func (ct *MyTime) UnmarshalJSON(b []byte) (err error) {
	s := strings.Trim(string(b), "\"")
	if s == "null" {
		ct.Time = time.Time{}
		return
	}
	ct.Time, err = time.Parse(layout, s)
	return
}

然后,就可以使用自己的时间类型了。


type Data struct {
	Name    string `json:"name"`
	Started MyTime `json:"started"`
}

var jsonStr = []byte(`
{
  "name": "new year",
  "started": "2021-01-01"
}`)

func main() {
	var data Data
	if err := json.Unmarshal(jsonStr, &data); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%+v\n", data)
}