前段时间碰到两处json.Unmarshal()时时间格式错误问题,一处是反序列化php提交的post参数,另一处是从kafka读取的python提交的message。都碰到时间格式不是rfc3339无法解析的问题。查了golang标准库 struct time 源码,发现time默认是以rfc3339的格式进行序列化反序列化的:
// MarshalJSON implements the json.Marshaler interface.
// The time is a quoted string in RFC 3339 format, with sub-second precision added if present.
func (t Time) MarshalJSON() ([]byte, error) {
if y := t.Year(); y < 0 || y >= 10000 {
// RFC 3339 is clear that years are 4 digits exactly.
// See golang.org/issue/4556#c15 for more discussion.
return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
}
b := make([]byte, 0, len(RFC3339Nano)+2)
b = append(b, '"')
b = t.AppendFormat(b, RFC3339Nano)
b = append(b, '"')
return b, nil
}
// UnmarshalJSON implements the json.Unmarshaler interface.
// The time is expected to be a quoted string in RFC 3339 format.
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
}
有一个方法是自定义一个time类型,重写MarshalJSON、UnmarshalJSON方法,不过这样当时还需要动到其他地方的代码,所以就没有这样修改。
所以还是希望php和python处传过来的就是rfc3339格式的时间字符串。
查了下rfc3339是一个标准的时间格式,每个语言都支持,对应到python语言中,就是datetime的iosformat格式:
In [1]: from datetime import datetime, timezone
In [2]: now = datetime.utcnow()
In [3]: print(now.isoformat())
2019-04-27T09:08:29.837820
以上做法生成的2019-04-27T09:08:29.837820
golang还是无法解析,查了原因是没有带时区信息,加上时区就好了。
In [5]: now = now.replace(tzinfo=timezone.utc)
In [6]: print(now.isoformat())
2019-04-27T09:08:29.837820+00:00
PHP中date也是可以取isoformat格式,就不举例了,还未掌握世界上最好的语言。。。。
所以个人觉得在传日期的时候尽量穿标准的rfc3339时间格式,避免使用自定义的时间格式(如2019-01-12 11:11:11
),会省去很多麻烦并避免很多问题。