Override the layout used by json.Marshal to format time.Time

前端 未结 3 1727
深忆病人
深忆病人 2021-01-05 07:53

In Golang, is there a way to make the generic encoding/json Marshal to use a different layout when Marshaling the time.Time fields?

Basical

相关标签:
3条回答
  • 2021-01-05 08:25

    As inspired by zeebo's answer and hashed out in the comments to that answer:

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

    package main
    
    import "fmt"
    import "time"
    import "encoding/json"
    
    type jsonTime struct {
        time.Time
        f string
    }
    
    func (j jsonTime) format() string {
        return j.Time.Format(j.f)
    }
    
    func (j jsonTime) MarshalText() ([]byte, error) {
        return []byte(j.format()), nil
    }
    
    func (j jsonTime) MarshalJSON() ([]byte, error) {
        return []byte(`"` + j.format() + `"`), nil
    }
    
    func main() {
        jt := jsonTime{time.Now(), time.Kitchen}
        if jt.Before(time.Now().AddDate(0, 0, 1)) { // 1
            x := map[string]interface{}{
                "foo": jt,
                "bar": "baz",
            }
            data, err := json.Marshal(x)
            if err != nil {
                panic(err)
            }
            fmt.Printf("%s", data)
        }
    }
    

    This solution embeds the time.Time into the jsonTime struct. Embedding promotes all of time.Time's methods to the jsonTime struct, allowing their use without explicit type conversion (see // 1).

    Embedding a time.Time has the downside of also promoting the MarshalJSON method, which the encoding/json marshaling code prioritizes higher than the MarshalText method for backwards compatibility reasons (MarshalText was added in Go 1.2, MarshalJSON predates that). As a result the default time.Time format is used instead of a custom format provided by MarshalText.

    To overcome this problem we override MarshalJSON for the jsonTime struct.

    0 讨论(0)
  • 2021-01-05 08:26

    Maybe something like this will work for you?

    package main
    
    import "fmt"
    import "time"
    import "encoding/json"
    
    type jsonTime struct {
    t time.Time
    f string
    }
    
    func (j jsonTime) MarshalText() ([]byte, error) {
    return []byte(j.t.Format(j.f)), nil
    }
    
    func main() {
    x := map[string]interface{}{
        "foo": jsonTime{t: time.Now(), f: time.Kitchen},
        "bar": "baz",
    }
    data, err := json.Marshal(x)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%s", data)
    }
    

    also available here: http://play.golang.org/p/D1kq5KrXQZ

    Just make a custom type that implements MarshalText the way you want it to show up.

    0 讨论(0)
  • 2021-01-05 08:34

    First, I highly recommend against using a time format other than the default RFC3339. It's a good time format, and can be parsed by any number of languages, so unless you are needing a different format because somebody else's API requires it, it's probably best to use the default.

    But, I've had to solve this problem in consuming other people's APIs, so here is one solution that shifts the bulk of the work to the Marshal/Unmarshal step, and leaves you with an ideal structure: http://play.golang.org/p/DKaTbV2Zvl

    0 讨论(0)
提交回复
热议问题