web-dev-qa-db-fra.com

Comment démarshal JSON en durées?

Quelle est la façon idiomatique de démarshal en time.Duration dans Go? Comment puis-je utiliser time.ParseDuration?

14
R3turnz

L'absence de méthodes de marshaling et de démasquage JSON sur time.Duration était un oubli malheureux. Espérons que cela devrait être résolu dans Go2 ( voir problème # 10275 ).

Vous pouvez cependant définir votre propre type autour de time.Duration qui prend en charge le marshaling vers la représentation sous forme de chaîne de la durée et le démasquage à partir des représentations numériques ou sous forme de chaîne. Voici un exemple d'une telle implémentation:

package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "time"
)

type Duration struct {
    time.Duration
}

func (d Duration) MarshalJSON() ([]byte, error) {
    return json.Marshal(d.String())
}

func (d *Duration) UnmarshalJSON(b []byte) error {
    var v interface{}
    if err := json.Unmarshal(b, &v); err != nil {
        return err
    }
    switch value := v.(type) {
    case float64:
        d.Duration = time.Duration(value)
        return nil
    case string:
        var err error
        d.Duration, err = time.ParseDuration(value)
        if err != nil {
            return err
        }
        return nil
    default:
        return errors.New("invalid duration")
    }
}

type Message struct {
    Elapsed Duration `json:"elapsed"`
}

func main() {
    msgEnc, err := json.Marshal(&Message{
        Elapsed: Duration{time.Second * 5},
    })
    if err != nil {
        panic(err)
    }
    fmt.Printf("%s\n", msgEnc)

    var msg Message
    if err := json.Unmarshal([]byte(`{"elapsed": "1h"}`), &msg); err != nil {
        panic(err)
    }
    fmt.Printf("%#v\n", msg)
}

https://play.golang.org/p/Zm6hpNR-ZJ2

28
Tim Cooper

Juste pour étendre la réponse précédente. Il y a une autre façon (très proche de celle de Tim)

type Duration time.Duration 

func (d Duration) MarshalJSON() ([]byte, error) {
    return json.Marshal(time.Duration(d).String())
}

func (d *Duration) UnmarshalJSON(b []byte) error {
    var v interface{}
    if err := json.Unmarshal(b, &v); err != nil {
        return err
    }
    switch value := v.(type) {
    case float64:
        *d = Duration(time.Duration(value))
        return nil
    case string:
        tmp, err := time.ParseDuration(value)
        if err != nil {
            return err
        }
        *d = Duration(tmp)
        return nil
    default:
        return errors.New("invalid duration")
    }
}
5
Alexander Polyakov