英文:
json unmarshal time that isn't in RFC 3339 format
问题
在Go语言中,处理不同时间格式的反序列化的适当方式是什么?encoding/json包似乎只接受RFC 3339格式,非常死板。我可以将其反序列化为字符串,然后将其转换为RFC 3339格式并进行解组,但我不太想这样做。有更好的解决方案吗?
英文:
What is the appropriate way to handle deserialization of different time formats in Go? The encoding/json package seems to be entirely rigid in only accepted RFC 3339. I can deserialize into a string, transform that into RFC 3339 and then unmarshal it but I don't really want to do that. Any better solutions?
答案1
得分: 75
你需要在自定义类型上实现json.Marshaler
/json.Unmarshaler
接口,并使用该类型替代原来的类型。以下是一个示例:
type CustomTime struct {
time.Time
}
const ctLayout = "2006/01/02|15:04:05"
func (ct *CustomTime) UnmarshalJSON(b []byte) (err error) {
s := strings.Trim(string(b), "\"")
if s == "null" {
ct.Time = time.Time{}
return
}
ct.Time, err = time.Parse(ctLayout, s)
return
}
func (ct *CustomTime) MarshalJSON() ([]byte, error) {
if ct.Time.IsZero() {
return []byte("null"), nil
}
return []byte(fmt.Sprintf("\"%s\"", ct.Time.Format(ctLayout))), nil
}
var nilTime = (time.Time{}).UnixNano()
func (ct *CustomTime) IsSet() bool {
return !ct.IsZero()
}
type Args struct {
Time CustomTime
}
var data = `
{"Time": "2014/08/01|11:27:18"}
`
func main() {
a := Args{}
fmt.Println(json.Unmarshal([]byte(data), &a))
fmt.Println(a.Time.String())
}
编辑:添加了CustomTime.IsSet()
函数,用于检查时间是否已设置,以供将来参考。
英文:
You will have to implement the json.Marshaler
/ json.Unmarshaler
interfaces on a custom type and use that instead, an example:
type CustomTime struct {
time.Time
}
const ctLayout = "2006/01/02|15:04:05"
func (ct *CustomTime) UnmarshalJSON(b []byte) (err error) {
s := strings.Trim(string(b), "\"")
if s == "null" {
ct.Time = time.Time{}
return
}
ct.Time, err = time.Parse(ctLayout, s)
return
}
func (ct *CustomTime) MarshalJSON() ([]byte, error) {
if ct.Time.IsZero() {
return []byte("null"), nil
}
return []byte(fmt.Sprintf("\"%s\"", ct.Time.Format(ctLayout))), nil
}
var nilTime = (time.Time{}).UnixNano()
func (ct *CustomTime) IsSet() bool {
return !ct.IsZero()
}
type Args struct {
Time CustomTime
}
var data = `
{"Time": "2014/08/01|11:27:18"}
`
func main() {
a := Args{}
fmt.Println(json.Unmarshal([]byte(data), &a))
fmt.Println(a.Time.String())
}
edit: added CustomTime.IsSet()
to check it was actually set or not, for future reference.
答案2
得分: 37
编码/解码是由time.Time
自身完成的,在MarshalJSON
和UnmarshalJSON
方法中。您可以创建自己的time.Time
类型并覆盖这些函数,以便根据您的需求与JSON一起使用。
type Time struct {
time.Time
}
// 无论如何都返回time.Now()!
func (t *Time) UnmarshalJSON(b []byte) error {
// 您现在可以根据需要彻底解析b
*t = Time{time.Now()}
return nil
}
type Config struct {
T Time
}
func main() {
c := Config{}
json.Unmarshal([]byte(`{"T": "bad-time"}`), &c)
fmt.Printf("%+v\n", c)
}
英文:
The encoding/decoding is done by time.Time
itself, in the MarshalJSON
and UnamrshalJSON
methods. You could create your own time.Time
type and override those functions to work with the json however you want.
type Time struct {
time.Time
}
// returns time.Now() no matter what!
func (t *Time) UnmarshalJSON(b []byte) error {
// you can now parse b as thoroughly as you want
*t = Time{time.Now()}
return nil
}
type Config struct {
T Time
}
func main() {
c := Config{}
json.Unmarshal([]byte(`{"T": "bad-time"}`), &c)
fmt.Printf("%+v\n", c)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论