programing

JSON은 공백으로 되어 있습니다.시간 필드

magicmemo 2023. 3. 2. 22:10
반응형

JSON은 공백으로 되어 있습니다.시간 필드

2개의 타임필드를 포함하는 구조체의 마셜링을 시도하고 있습니다.하지만 시간 값이 있는 필드만 통과했으면 합니다.그래서 지금 쓰고 있어요.json:",omitempty"효과가 없어요.

날짜 값을 so json으로 설정할 수 있는 것은 무엇입니까?Marshal은 그것을 빈 값(0)으로 취급하고 json 문자열에 포함하지 않습니까?

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

실제 결과:

{'타임 스탬프':2015-09-18T00:00:00Z", "날짜":0001-01-01T00: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))
}

omitempty태그 옵션은 와 함께 동작하지 않습니다.time.Time이지만struct. 구조체에는 "0" 값이 있지만 모든 필드에 0 값이 있는 구조체 값입니다.이 값은 "유효한" 값이므로 "빈"으로 처리되지 않습니다.

그러나 단순히 포인터로 변경하는 것만으로:*time.Time동작합니다(nil포인터는 json 마샬링/언마샬링의 경우 "empty"로 취급됩니다.따라서 이 경우 커스텀을 쓸 필요가 없습니다.

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"}

바둑 놀이터에서 시도해 보세요.

포인터로 변경할 수 없거나 포인터로 변경할 수 없는 경우에도 커스텀과 를 실장하면 원하는 것을 실현할 수 있습니다.이 경우 이 방법을 사용하여 다음 중 하나를 선택할 수 있습니다.time.Timevalue는 제로 값입니다.

커스텀 marshal 포맷에 대한 자체 시간 유형을 정의하고 대신 어디에서나 사용할 수 있습니다.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 케이스에는 두 개의 시간 필드가 있어 훨씬 더 복잡해집니다.(둘 다 비어 있지 않은지 확인해야 합니다.)

이를 달성하기 위한 더 나은 방법이 있을 수 있으므로 코멘트는 환영합니다.

언급URL : https://stackoverflow.com/questions/32643815/json-omitempty-with-time-time-field

반응형