为了账号安全,请及时绑定邮箱和手机立即绑定

JSON omitempty with time.Time 字段

JSON omitempty with time.Time 字段

Go
30秒到达战场 2021-11-08 16:03:27
尝试对包含 2 个时间字段的结构进行 json 编组。但我只希望该字段具有时间价值。所以我正在使用json:",omitempty"但它不起作用。我可以将 Date 值设置为什么,以便 json.Marshal 将其视为空(零)值而不将其包含在 json 字符串中?游乐场:http : //play.golang.org/p/QJwh7yBJlo实际结果:{"时间戳":"2015-09-18T00:00:00Z","日期":"0001-01-01T00:00:00Z"}期望的结果:{"时间戳":"2015-09-18T00:00:00Z"}代码:package mainimport (    "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))}
查看完整描述

3 回答

?
隔江千里

TA贡献1906条经验 获得超10个赞

该omitempty标签选项不能正常工作time.Time,因为它是一个struct。结构体有一个“零”值,但这是一个结构体值,其中所有字段的值都为零。这是一个“有效”值,因此不被视为“空”。


但是通过简单地将其更改为指针:*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值是否为零值。


查看完整回答
反对 回复 2021-11-08
?
呼啦一阵风

TA贡献1802条经验 获得超6个赞

您可以为自定义元帅格式定义自己的时间类型,并在任何地方使用它 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)

}


查看完整回答
反对 回复 2021-11-08
?
RISEBY

TA贡献1856条经验 获得超5个赞

作为 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/借用


OPs 案例有两个时间字段,这会使它变得更加复杂。(你必须检查两者都不是,两者都是空的!)


可能有更好的方法来实现这一点,所以欢迎提出意见。


查看完整回答
反对 回复 2021-11-08
  • 3 回答
  • 0 关注
  • 226 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信