Tijdstempel opmaken in uitgaande JSON

Ik heb onlangs met Go gespeeld en het is geweldig. Waar ik niet achter kan komen (na het doornemen van documentatie en blogposts) is hoe ik het type time.Timekan laten formatteren in het formaat dat ik wil wanneer het is gecodeerd door json.NewEncoder.Encode

Hier is een minimaal codevoorbeeld:

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

Idealiter zou ik een verzoek willen sturen en het veld Stempel terug willen krijgen als iets als May 15, 2014en niet 2014-05-16T08:28:06.801064-04:00

Maar ik weet niet precies hoe, ik weet dat ik json:stampkan toevoegen aan de declaratie van het documenttype om het veld te coderen met de naamstempel in plaats van met Stempel, maar ik doe dat niet Ik weet niet hoe dat soort dingen heten, dus ik weet niet eens waar ik op moet googlen om erachter te komen of daar ook een soort opmaakoptie in zit.

Heeft iemand een link naar een voorbeeld- of goede documentatiepagina over het onderwerp van die typemarkeringen (of hoe ze ook worden genoemd) of hoe ik de JSON-encoder kan vertellen om time.Timevelden?

Ter referentie heb ik deze pagina’s bekeken: hieren hieren natuurlijk, in de officiële documenten


Antwoord 1, autoriteit 100%

Wat u kunt doen is time.Time inpakken als uw eigen aangepaste type en ervoor zorgen dat de interface Marshalerwordt geïmplementeerd:

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

Dus wat je zou doen is zoiets als:

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
}

en maak document:

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

en laat uw initialisatie er als volgt uitzien:

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

En dat is het zowat. Als je unmarshaling wilt, is er ook de Unmarshaler-interface.


Antwoord 2, autoriteit 55%

Misschien is een andere manier interessant voor iemand. Ik wilde het aliastype voor Tijd vermijden.

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

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


Antwoord 3, autoriteit 30%

Ik zou NIET gebruiken:

type JSONTime time.Time

Ik zou het alleen voor primitieven gebruiken (string, int, …). In het geval van time.Timewat een struct is, zou ik het elke keer moeten casten als ik een time.Timemethode wil gebruiken.

Ik zou dit in plaats daarvan doen (insluiten):

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
}

Het is niet nodig om tnaar tijd te casten. Het enige verschil is dat de nieuwe instantie NIET wordt gemaakt door JSONTime(time.Now())maar door JSONTime{time.Now()}


Antwoord 4, autoriteit 6%

Maar ik weet niet precies hoe, ik weet dat ik json:stamp kan toevoegen aan de documenttypedeclaratie om het veld te coderen met de naamstempel in plaats van Stamp, maar ik weet niet wat die typen dingen worden genoemd, dus ik weet niet eens waar ik op moet googlen om erachter te komen of daar ook een soort opmaakoptie in zit.

Je bedoelt tags. Maar deze zullen je niet helpen met je opmaakprobleem.

De tekenreeksrepresentatie die u voor uw tijd krijgt, wordt geretourneerd door MarshalJSONgeïmplementeerd door Time.

U kunt uw eigen MarshalJSON-methode implementeren door de relevante bits te kopiëren uit de Timeimplementatiedoor ofwel time.Timein te sluiten of het inpakken. Inpakvoorbeeld (Klik om af te spelen):

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
}

Other episodes