随时间变化.时间字段



尝试json封送一个包含两个时间字段的结构。但是我只希望字段有时间值的时候通过。所以我使用json:",omitempty",但它不起作用。

我可以将Date值设置为so json。Marshal会把它当作一个空(零)值,不包括在json字符串?

游乐场:http://play.golang.org/p/QJwh7yBJlo

实际结果:

{"时间戳":"2015 - 09 - 18 t00:00:00z","日期":"0001 - 01 - 01 t00:00:00z"}

期望结果:

{"时间戳":"2015 - 09 - 18岁t00: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))
}

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值是否为零值。

您可以为自定义marshal格式定义self Time类型,并在任何地方使用它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)
}

作为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的情况有两个时间字段,这将使它更加复杂。(您必须检查neither, either和both是否为空!)

可能有更好的方法来实现这一点,所以欢迎评论。

最新更新