Как преобразовать время в 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))
}
Другие вопросы по тегам