web-dev-qa-db-fra.com

Format Horodatage dans le JSON sortant à Golang?

Je joue avec Go récemment et c'est génial. La seule chose que je n'arrive pas à comprendre (après avoir consulté la documentation et les billets de blog) est comment obtenir le time.Time taper pour formater le format que je voudrais quand il est encodé par json.NewEncoder.Encode

Voici un exemple de code minimal:

package main

type Document struct {
    Name        string
    Content     string
    Stamp       time.Time
    Author      string
}

func sendResponse(data interface{}, w http.ResponseWriter, r * http.Request){
     _, err := json.Marshal(data)
    j := json.NewEncoder(w)
    if err == nil {
        encodedErr := j.Encode(data)
        if encodedErr != nil{
            //code snipped
        }
    }else{
       //code snipped
    }
}

func main() {
    http.HandleFunc("/document", control.HandleDocuments)
    http.ListenAndServe("localhost:4000", nil)
}

func HandleDocuments(w http.ResponseWriter,r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    w.Header().Set("Access-Control-Allow-Origin", "*")

    switch r.Method {
        case "GET": 
            //logic snipped
            testDoc := model.Document{"Meeting Notes", "These are some notes", time.Now(), "Bacon"}    
            sendResponse(testDoc, w,r)
            }
        case "POST":
        case "PUT":
        case "DELETE":
        default:
            //snipped
    }
}

Idéalement, j'aimerais envoyer une demande et obtenir le champ Timbre comme suit: May 15, 2014 et pas 2014-05-16T08:28:06.801064-04:00

Mais je ne sais pas trop comment, je sais que je peux ajouter json:stamp à la déclaration de type de document pour que le champ soit encodé avec le nom stamp au lieu de stamp, mais je ne sais pas comment ces types s'appellent, donc je ne suis même pas sûr de ce qu'il faut rechercher sur Google s’il existe également un type d’option de formatage.

Quelqu'un a-t-il un lien vers un exemple ou une bonne page de documentation sur le sujet de ces balises (ou le nom de la balise) ou sur la façon dont je peux dire à l'encodeur JSON de gérer time.Time des champs?

Juste pour référence, j'ai regardé ces pages: ici et ici et bien sûr, aux documents officiels

45
EdgeCaseBerg

Ce que vous pouvez faire est, encapsulez time.Time comme votre propre type personnalisé et faites-le implémenter l'interface Marshaler:

type Marshaler interface {
    MarshalJSON() ([]byte, error)
}

Donc, ce que vous feriez est quelque chose comme:

type JSONTime time.Time

func (t JSONTime)MarshalJSON() ([]byte, error) {
    //do your serializing here
    stamp := fmt.Sprintf("\"%s\"", time.Time(t).Format("Mon Jan _2"))
    return []byte(stamp), nil
}

et faire un document:

type Document struct {
    Name        string
    Content     string
    Stamp       JSONTime
    Author      string
}

et que votre initiation ressemble à:

 testDoc := model.Document{"Meeting Notes", "These are some notes", JSONTime(time.Now()), "Bacon"}    

Et c'est à peu près tout. Si vous souhaitez supprimer le métissage, il existe également l'interface Unmarshaler.

83
Not_a_Golfer

Peut-être qu'une autre façon sera intéressante pour quelqu'un. Je voulais éviter d'utiliser le type d'alias pour Time.

type Document struct {
    Name    string
    Content string
    Stamp   time.Time
    Author  string
}

func (d *Document) MarshalJSON() ([]byte, error) {
    type Alias Document
    return json.Marshal(&struct {
        *Alias
        Stamp string `json:"stamp"`
    }{
        Alias: (*Alias)(d),
        Stamp: d.Stamp.Format("Mon Jan _2"),
    })
}

Source: http://choly.ca/post/go-json-marshalling/

39
s7anley

Je ne voudrais pas utiliser:

type JSONTime time.Time

Je ne l'utiliserais que pour les primitives (string, int, ...). Dans le cas de time.Time Qui est une structure, je devrais le lancer à chaque fois que je veux utiliser une méthode time.Time.

Je ferais ceci à la place (intégration):

type JSONTime struct {
    time.Time
}

func (t JSONTime)MarshalJSON() ([]byte, error) {
    //do your serializing here
    stamp := fmt.Sprintf("\"%s\"", t.Format("Mon Jan _2"))
    return []byte(stamp), nil
}

Pas besoin de lancer t à temps. La seule différence est que la nouvelle instance n'est PAS créée par JSONTime(time.Now()) mais par JSONTime{time.Now()}

15
user2800844

Mais je ne sais pas trop comment, je sais que je peux ajouter json: stamp à la déclaration de type de document pour que le champ soit codé avec le tampon de nom au lieu de tampon, mais je ne sais pas comment ces types de choses s'appellent. Je ne sais même pas quoi chercher sur Google pour savoir s’il existe également une option de formatage.

Vous voulez dire tags . Mais cela ne vous aidera pas avec votre problème de formatage.

La représentation sous forme de chaîne que vous obtenez pour votre temps est retournée par MarshalJSON implémenté par Time .

Vous pouvez aller de l'avant et implémenter votre propre méthode MarshalJSON en copiant les bits pertinents de l'implémentation de Time en incorporant time.Time ou l'envelopper. Exemple de wrapping ( Cliquez pour lire ):

type ShortDateFormattedTime time.Time

func (s ShortDateFormattedTime) MarshalJSON() ([]byte, error) {
    t := time.Time(s)
    if y := t.Year(); y < 0 || y >= 10000 {
        return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
    }

    return []byte(t.Format(`"Jan 02, 2006"`)), nil
}
5
nemo