Как преобразовать время в UTC перед маршалингом в формате JSON в Go?
Я пытаюсь определитьTime
структура, реализующаяMarshaler
такой интерфейс, что при маршалинге в JSON он представляется в форматеYYYY-mm-ddTHH:MM:SSZ
, то есть время конвертируется в формат UTC и округляется до ближайшей секунды. Я пробовал следующую программу:
package main
import (
"encoding/json"
"fmt"
"log"
"time"
)
type Time struct {
time.Time
}
func (t *Time) MarshalJSON() ([]byte, error) {
return []byte(t.Time.UTC().Round(time.Second).Format(time.RFC3339)), nil
}
func main() {
tm := time.Now()
// tm := time.Now().UTC().Round(time.Second)
tmJSON, err := json.Marshal(tm)
if err != nil {
log.Fatalf("marshal time: %v", err)
}
fmt.Println(string(tmJSON))
}
Однако, когда я запускаю это, он печатает
> go run main.go
"2022-12-07T16:32:51.494597-08:00"
Если, напротив, я прохожуtime.Now().UTC().Round(time.Second)
в качестве входных данных для маршалинга (т. е. используйте закомментированную строку в приведенном выше фрагменте), я получаю желаемый результат:
> go run main.go
"2022-12-08T00:41:10Z"
Мой вопрос: почему я не могу выполнить преобразование в UTC и округление до ближайшей секунды вMarshalJSON
сам метод?
1 ответ
Вы можете использоватьAppendFormat
чтобы преобразовать вашу временную строку в буфер.
Также в вашем вопросе вы не инициализируете свойTime
структура для маршаллинга.
Вот вероятное решение
package main
import (
"encoding/json"
"errors"
"fmt"
"log"
"time"
)
type Time struct {
time.Time
}
func (t *Time) MarshalJSON() ([]byte, error) {
if y := t.Year(); y < 0 || y >= 10000 {
return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
}
b := make([]byte, 0, len(time.RFC3339)+2)
b = append(b, '"')
b = t.UTC().Round(time.Second).AppendFormat(b, time.RFC3339)
b = append(b, '"')
return b, nil
}
func main() {
now := time.Now()
mt := &Time{now}
bytArr, err := json.Marshal(mt)
if err != nil {
log.Fatalf("marshal time: %v", err)
}
fmt.Println(string(bytArr))
}