2015-09-18 15 views
10

Versuch, Marshall eine Struktur, die 2 Zeitfelder enthält. Aber ich möchte nur, dass das Feld durchkommt, wenn es einen Zeitwert hat. Ich verwende also json:",omitempty", aber es funktioniert nicht.Golang JSON omitemperty Mit time.Time Feld

Was kann ich den Date-Wert auf so json.Marshal wird es wie ein leerer (Null) Wert behandeln und nicht in der JSON-String enthalten?

Spielplatz: http://play.golang.org/p/QJwh7yBJlo

tatsächliches Ergebnis:

{ "Timestamp": "2015-09-18T00: 00: 00Z", "Datum": "0001-01-01T00: 00: 00Z "}

erwünschtes Ergebnis:

{ "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)) 
} 
+4

Die Funktion [funktioniert nicht mit time.Time] (https://github.com/golang/go/blob/1fd78e1f600d10475b85381427bda9f14f86e0f0/src/encoding/json/encode.go#L278-L294). –

+1

Der einfachste Weg zu Ihrem Ziel wäre es, MyStruct http://golang.org/pkg/encoding/json/#Unmarshaler implementieren zu lassen. – Volker

+0

Gut zu wissen und guter Rat. Vielen Dank! –

Antwort

26

Die Tag-Option omitempty funktioniert nicht mit time.Time, da es sich um eine struct handelt. Es gibt einen "Null" -Wert für Strukturen, aber das ist ein Strukturwert, bei dem alle Felder ihre Nullwerte haben. Dies ist ein "gültiger" Wert und wird daher nicht als "leer" behandelt.

Aber durch einfaches Ändern in einen Zeiger: *time.Time, wird es funktionieren (nil Zeiger werden behandelt wie "leer" für Json Marshalling/Unmarshalling). Also keine Notwendigkeit, individuelle schreiben Marshaler in diesem Fall:

type MyStruct struct { 
    Timestamp *time.Time `json:",omitempty"` 
    Date  *time.Time `json:",omitempty"` 
    Field  string  `json:",omitempty"` 
} 

es verwenden:

ts := time.Date(2015, 9, 18, 0, 0, 0, 0, time.UTC) 
ms := MyStruct{ 
    Timestamp: &ts, 
    Field:  "", 
} 

Ausgang (je nach Wunsch):

{"Timestamp":"2015-09-18T00:00:00Z"} 

Versuchen Sie es auf dem Go Playground.

Wenn Sie es nicht zu einem Zeiger ändern können oder möchten, können Sie dennoch erreichen, was Sie wollen, indem Sie eine benutzerdefinierte Marshaler und Unmarshaler implementieren. Wenn Sie dies tun, können Sie die Time.IsZero() Methode verwenden, um zu entscheiden, ob ein time.Time Wert der Nullwert ist.

+0

Das ist eine großartige Antwort. Vielen Dank! –

2

Sie können Sie definieren selbst Zeittyp für benutzerdefinierte Marshal-Format und Verwendung es überall statt 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) 
}