英文:
How to convert a time to UTC before marshaling as JSON in 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"
我的问题是:为什么我不能在MarshalJSON
方法本身中执行UTC转换和四舍五入到最近的秒?
英文:
I'm trying to define a Time
struct which implements the Marshaler
interface such that, when it is marshaled to JSON, it is represented in the format YYYY-mm-ddTHH:MM:SSZ
, that is, the time is converted to UTC and rounded to the nearest second. I've tried the following program:
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))
}
When I run this, however, it prints
> go run main.go
"2022-12-07T16:32:51.494597-08:00"
If, by contrast, I pass in time.Now().UTC().Round(time.Second)
as the input to be marshaled (i.e., use the commented-out line in the snippet above), I get the desired output:
> go run main.go
"2022-12-08T00:41:10Z"
My question is: why can't I perform the conversion to UTC and rounding to the nearest second in the MarshalJSON
method itself?
答案1
得分: 1
你想做什么?
我尝试运行你的MarshalJSON
函数,结果符合预期。
以下是我尝试做的事情:
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().UTC()
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))
marshal_time := Time{time.Now().UTC()}
byt_arr, _ := marshal_time.MarshalJSON()
fmt.Println(string(byt_arr))
}
我得到了以下输出:
"2022-12-08T04:41:59Z"
2022-12-08T04:41:59Z
第一行是你之前的输出,第二行是你的MarshalJSON
函数的输出。
英文:
what are you trying to do?
I tried running your MarshalJSON
function and it works as expected
here is what I tried to do:
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().UTC()
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))
marshal_time := Time{time.Now().UTC()}
byt_arr, _ := marshal_time.MarshalJSON()
fmt.Println(string(byt_arr))
}
and i got the following output:
"2022-12-08T04:41:59Z"
2022-12-08T04:41:59Z
The first line is your previous output and the second output is of your MarshalJSON
function.
答案2
得分: 0
你可以使用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))
}
希望对你有帮助!
英文:
You can use AppendFormat
to convert your time string into buffer.
Also in your question you are not initialising your Time
struct for Marshalling.
Here is a probable solution
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))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论