Подтвердить что ты не робот

Форматировать временную метку в исходящем JSON в Голанге?

Я играю с Go недавно, и это потрясающе. То, что я не могу понять (после просмотра документации и сообщений в блогах), заключается в том, как получить тип time.Time для форматирования в любом формате, который мне нужен, когда он будет закодирован json.NewEncoder.Encode

Здесь минимальный пример кода:

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

В идеале я бы хотел отправить запрос и вернуть поле Stamp как-то вроде May 15, 2014, а не 2014-05-16T08:28:06.801064-04:00

Но я не совсем уверен, как, я знаю, что я могу добавить json:stamp в объявление типа документа, чтобы получить поле для кодирования с печатью имени вместо Stamp, но я не знаю, что эти типы вещи вызываются, поэтому я даже не уверен, что делать в Google, чтобы узнать, есть ли в нем какой-то вариант форматирования.

Есть ли у кого-нибудь ссылка на пример или на хорошую страницу документации по теме разметки типа (или что бы они ни называли) или на то, как я могу сказать, что кодер JSON обрабатывает поля time.Time?

Просто для справки, я просмотрел эти страницы: здесь и здесь и, конечно, в официальных документах

4b9b3361

Ответ 1

Что вы можете сделать, это время wrap.Time как ваш собственный пользовательский тип и заставить его реализовать интерфейс Marshaler:

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

Итак, что бы вы сделали, это что-то вроде:

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
}

и сделайте документ:

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

и ваша инициализация выглядит следующим образом:

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

И об этом. Если вы хотите unmarshaling, есть и интерфейс Unmarshaler.

Ответ 2

Возможно, для кого-то будет интересным другой способ. Я хотел избежать использования псевдонима для 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"),
    })
}

Источник: http://choly.ca/post/go-json-marshalling/

Ответ 3

Я бы не использовал:

type JSONTime time.Time

Я бы использовал его только для примитивов (string, int,...). В случае time.Time, который является структурой, мне нужно будет использовать его каждый раз, когда я хочу использовать любой метод time.Time.

Я бы сделал это вместо (наследование):

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
}

Не нужно бросать t во времени. Единственное различие заключается в том, что новый экземпляр НЕ создан JSONTime(time.Now()), а JSONTime{time.Now()}

Ответ 4

Но я не совсем уверен, как, я знаю, я могу добавить json: штамп к объявлению типа документа, чтобы получить поле, которое будет закодировано с помощью штампа вместо Stamp, но я не знаю, что эти типы вещи вызываются, поэтому я даже не уверен, что делать в Google, чтобы узнать, есть ли в нем какой-то вариант форматирования.

Вы имеете в виду теги. Но это не поможет вам с проблемой форматирования.

Строковое представление, которое вы получаете за свое время, возвращается MarshalJSON, реализованное Time.

Вы можете продолжить и реализовать свой собственный метод MarshalJSON, скопировав соответствующие биты из Time путем внедрения time.Time или обертывание. Пример упаковки (Нажмите, чтобы воспроизвести):

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

Так идеально, я бы хотел отправить запрос и вернуть поле Stamp что-то вроде 15 мая 2014 года, а не 2014-05-16T08: 28: 06.801064-04: 00

Но я не совсем уверен, как

Вы можете сделать это, отформатировав time.Now(), перейдя к model.Document() так, чтобы

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

Это будет отформатировать time.Now() как месяц, год

Если time.Now() - 2014-05-16T08:28:06.801064-04:00, он будет отформатирован как May 16, 2014

Вдохновленный примером в http://golang.org/pkg/time/#example_Time_Format