Форматировать временную метку в исходящем 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
?
Просто для справки, я просмотрел эти страницы: здесь и здесь и, конечно, в официальных документах
Ответы
Ответ 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