Golang JSON omitempty with time.Time Field

时间:2015-09-18 04:20:34

标签: json go time struct

尝试json Marshal包含2个时间字段的结构。但是如果它有时间价值,我只希望该字段能够通过。所以我使用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 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))
}

3 个答案:

答案 0 :(得分:59)

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上尝试。

如果您不能或不想将其更改为指针,您仍然可以通过实施自定义MarshalerUnmarshaler来实现您的目标。如果您这样做,则可以使用Time.IsZero()方法来确定time.Time值是否为零值。

答案 1 :(得分:2)

您可以为自定义编组格式定义自己的时间类型,并在任何地方使用它time.Time

http://play.golang.org/p/S9VIWNAaVS

package main

import "fmt"
import "time"
import "encoding/json"

type MyTime struct{
    *time.Time
}

func (t MyTime) MarshalJSON() ([]byte, error) {
        return []byte(t.Format("\"2006-01-02T15:04:05Z\"")), 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) {
        // Fractional seconds are handled implicitly by Parse.
        tt, err := time.Parse("\"2006-01-02T15:04:05Z\"", 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)
}

答案 2 :(得分:1)

作为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案件有两个时间字段,这将使其变得更加复杂。 (您不必检查任何一个,两个都为空!)

可能有更好的方法来实现这一目标,因此欢迎发表评论。