英文:
JSON omitempty With time.Time Field
问题
尝试将包含两个时间字段的结构体进行JSON编组(Marshal)。但是,我只希望在时间字段具有值时才传递该字段。因此,我使用了json:",omitempty"
,但它没有起作用。
我应该将Date值设置为什么,以便json.Marshal将其视为空(零)值并将其排除在JSON字符串之外?
Playground链接:http://play.golang.org/p/QJwh7yBJlo
实际结果:
{"Timestamp":"2015-09-18T00:00:00Z","Date":"0001-01-01T00:00:00Z"}
期望结果:
{"Timestamp":"2015-09-18T00:00:00Z"}
代码:
package main
import (
"encoding/json"
"fmt"
"time"
)
type MyStruct struct {
Timestamp time.Time `json:",omitempty"`
Date time.Time `json:",omitempty"`
Field string `json:",omitempty"`
}
func main() {
ms := MyStruct{
Timestamp: time.Date(2015, 9, 18, 0, 0, 0, 0, time.UTC),
Field: "",
}
bb, err := json.Marshal(ms)
if err != nil {
panic(err)
}
fmt.Println(string(bb))
}
英文:
Trying to json Marshal a struct that contains 2 time fields. But I only want the field to come through if it has a time value. So I'm using json:",omitempty"
but it's not working.
What can I set the Date value to so json.Marshal will treat it like an empty (zero) value and not include it in the json string?
Playground: http://play.golang.org/p/QJwh7yBJlo
Actual Outcome:
> {"Timestamp":"2015-09-18T00:00:00Z","Date":"0001-01-01T00:00:00Z"}
Desired Outcome:
> {"Timestamp":"2015-09-18T00:00:00Z"}
Code:
package main
import (
"encoding/json"
"fmt"
"time"
)
type MyStruct struct {
Timestamp time.Time `json:",omitempty"`
Date time.Time `json:",omitempty"`
Field string `json:",omitempty"`
}
func main() {
ms := MyStruct{
Timestamp: time.Date(2015, 9, 18, 0, 0, 0, 0, time.UTC),
Field: "",
}
bb, err := json.Marshal(ms)
if err != nil {
panic(err)
}
fmt.Println(string(bb))
}
答案1
得分: 145
omitempty
标签选项在处理time.Time
时不起作用,因为它是一个结构体。结构体有一个“零”值,但这是一个结构体值,其中所有字段都具有它们的零值。这是一个“有效”的值,因此不被视为“空”。
但是,通过将其更改为指针:*time.Time
,它将起作用(nil
指针在json编组/解组时被视为“空”)。因此,在这种情况下不需要编写自定义的Marshaler
:
type MyStruct struct {
Timestamp *time.Time `json:",omitempty"`
Date *time.Time `json:",omitempty"`
Field string `json:",omitempty"`
}
使用它:
ts := time.Date(2015, 9, 18, 0, 0, 0, 0, time.UTC)
ms := MyStruct{
Timestamp: &ts,
Field: "",
}
输出(如所需):
{"Timestamp":"2015-09-18T00:00:00Z"}
在Go Playground上尝试一下。
如果您不能或不想将其更改为指针,仍然可以通过实现自定义的Marshaler
和Unmarshaler
来实现您想要的效果。如果这样做,您可以使用Time.IsZero()
方法来判断time.Time
值是否为零值。
英文:
The omitempty
tag option does not work with time.Time
as it is a struct
. There is a "zero" value for structs, but that is a struct value where all fields have their zero values. This is a "valid" value, so it is not treated as "empty".
But by simply changing it to a pointer: *time.Time
, it will work (nil
pointers are treated as "empty" for json marshaling/unmarshaling). So no need to write custom Marshaler
in this case:
type MyStruct struct {
Timestamp *time.Time `json:",omitempty"`
Date *time.Time `json:",omitempty"`
Field string `json:",omitempty"`
}
Using it:
ts := time.Date(2015, 9, 18, 0, 0, 0, 0, time.UTC)
ms := MyStruct{
Timestamp: &ts,
Field: "",
}
Output (as desired):
{"Timestamp":"2015-09-18T00:00:00Z"}
Try it on the Go Playground.
If you can't or don't want to change it to a pointer, you can still achieve what you want by implementing a custom Marshaler
and Unmarshaler
. If you do so, you can use the Time.IsZero()
method to decide if a time.Time
value is the zero value.
答案2
得分: 8
你可以为自定义的编组格式定义自己的Time类型,并在所有地方使用它,而不是使用time.Time
。
以下是代码的翻译:
package main
import (
"bytes"
"encoding/json"
"fmt"
"time"
)
type MyTime struct {
*time.Time
}
func (t MyTime) MarshalJSON() ([]byte, error) {
return []byte(t.Format("\"" + time.RFC3339 + "\"")), nil
}
// UnmarshalJSON implements the json.Unmarshaler interface.
// The time is expected to be a quoted string in RFC 3339 format.
func (t *MyTime) UnmarshalJSON(data []byte) (err error) {
// by convention, unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op.
if bytes.Equal(data, []byte("null")) {
return nil
}
// Fractional seconds are handled implicitly by Parse.
tt, err := time.Parse("\""+time.RFC3339+"\"", string(data))
*t = MyTime{&tt}
return
}
func main() {
t := time.Now()
d, err := json.Marshal(MyTime{&t})
fmt.Println(string(d), err)
var mt MyTime
json.Unmarshal(d, &mt)
fmt.Println(mt)
}
希望对你有帮助!
英文:
You may define you self Time type for custom marshal format, and use it everywhere instead time.Time
https://play.golang.org/p/C8nIR1uZAok
package main
import (
"bytes"
"encoding/json"
"fmt"
"time"
)
type MyTime struct {
*time.Time
}
func (t MyTime) MarshalJSON() ([]byte, error) {
return []byte(t.Format("\"" + time.RFC3339 + "\"")), nil
}
// UnmarshalJSON implements the json.Unmarshaler interface.
// The time is expected to be a quoted string in RFC 3339 format.
func (t *MyTime) UnmarshalJSON(data []byte) (err error) {
// by convention, unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op.
if bytes.Equal(data, []byte("null")) {
return nil
}
// Fractional seconds are handled implicitly by Parse.
tt, err := time.Parse("\""+time.RFC3339+"\"", string(data))
*t = MyTime{&tt}
return
}
func main() {
t := time.Now()
d, err := json.Marshal(MyTime{&t})
fmt.Println(string(d), err)
var mt MyTime
json.Unmarshal(d, &mt)
fmt.Println(mt)
}
答案3
得分: 4
作为对icza答案的跟进,这是一个自定义的编组程序,它省略了一个空日期字段,但保持其他字段不变。
func (ms *MyStruct) MarshalJSON() ([]byte, error) {
type Alias MyStruct
if ms.Timestamp.IsZero() {
return json.Marshal(&struct {
Timestamp int64 `json:",omitempty"`
*Alias
}{
Timestamp: 0,
Alias: (*Alias)(ms),
})
} else {
return json.Marshal(&struct {
*Alias
}{
Alias: (*Alias)(ms),
})
}
}
这是从http://choly.ca/post/go-json-marshalling/借鉴的。
原始问题有两个时间字段,这会使问题变得更加复杂(你需要检查两个字段都为空、其中一个为空还是都不为空!)。
可能有更好的方法来实现这一点,所以欢迎评论。
英文:
As a follow up to icza's answer here is a custom marshaller that omits an empty date field but keeps the rest of the fields unchanged.
func (ms *MyStruct) MarshalJSON() ([]byte, error) {
type Alias MyStruct
if ms.Timestamp.IsZero() {
return json.Marshal(&struct {
Timestamp int64 `json:",omitempty"`
*Alias
}{
Timestamp: 0,
Alias: (*Alias)(ms),
})
} else {
return json.Marshal(&struct {
*Alias
}{
Alias: (*Alias)(ms),
})
}
}
This borrows from http://choly.ca/post/go-json-marshalling/
The OPs case has two time fields which would make it much more complicated. (you'd have to check for neither, either and both being empty!)
There may be better ways to achieve this, so comments are welcome.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论