How to convert a time to UTC before marshaling as JSON in Go?

huangapple go评论69阅读模式
英文:

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 (
	&quot;encoding/json&quot;
	&quot;errors&quot;
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;time&quot;
)

type Time struct {
	time.Time
}

func (t *Time) MarshalJSON() ([]byte, error) {
	if y := t.Year(); y &lt; 0 || y &gt;= 10000 {
		return nil, errors.New(&quot;Time.MarshalJSON: year outside of range [0,9999]&quot;)
	}

	b := make([]byte, 0, len(time.RFC3339)+2)
	b = append(b, &#39;&quot;&#39;)
	b = t.UTC().Round(time.Second).AppendFormat(b, time.RFC3339)
	b = append(b, &#39;&quot;&#39;)
	return b, nil
}

func main() {
	now := time.Now()
	mt := &amp;Time{now}
	bytArr, err := json.Marshal(mt)
	if err != nil {
		log.Fatalf(&quot;marshal time: %v&quot;, err)
	}

	fmt.Println(string(bytArr))
}

huangapple
  • 本文由 发表于 2022年12月8日 08:42:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/74724346.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定