2015-09-18 2 views
10

Попытка json Marshal создать структуру, содержащую 2 поля времени. Но я хочу, чтобы поле получилось, если оно имеет значение времени. Поэтому я использую json:",omitempty", но он не работает.Golang JSON omitempty С тегом time.Time

Что я могу установить для значения 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)) 
} 
+4

Функция [не работает со временем. Время] (https://github.com/golang/go/blob/1fd78e1f600d10475b85381427bda9f14f86e0f0/src/encoding/json/encode.go#L278-L294). –

+1

Возможно, самым простым способом для вашей цели было бы позволить MyStruct реализовать http://golang.org/pkg/encoding/json/#Unmarshaler. – Volker

+0

Полезно знать и хороший совет. Благодаря! –

ответ

26

Параметр тега omitempty не работает с time.Time, так как это struct. Для structs существует «нулевое» значение, но это значение структуры, где все поля имеют нулевые значения. Это «действительное» значение, поэтому оно не рассматривается как «пустое».

Но просто изменив его на указатель: *time.Time, он будет работать (nil указатели считаются «пустыми» для json marshaling/unmarshaling). Так что не нужно писать пользовательские 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:  "", 
} 

Output (по желанию):

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

Попробуйте на Go Playground.

Если вы не можете или не хотите менять его на указатель, вы все равно можете достичь того, чего хотите, реализовав пользовательские настройки Marshaler и Unmarshaler. Если вы это сделаете, вы можете использовать метод Time.IsZero(), чтобы решить, является ли значение time.Time нулевым значением.

+0

Это отличный ответ. Благодаря! –

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) 
} 
Смежные вопросы