Fel*_*sén 3 formatting time go
我正在尝试为自定义类型编写一个解组函数。考虑下面的代码(游乐场)
package main
import (
"encoding/json"
"fmt"
"strings"
"time"
)
type Time time.Time
func (st *Time) UnmarshalJSON(b []byte) error {
// "2021-05-21T03:10:20.958450" -> "2021-05-21T03:10:20.958450Z"
s := strings.Trim(string(b), "\"")
t, err := time.Parse(time.RFC3339, fmt.Sprintf("%s%s", s, "Z"))
if err != nil {
return fmt.Errorf("parse time: %w", err)
}
*st = Time(t)
return nil
}
type User struct {
Name string
TS Time
}
const data = `{"id":3, "name":"Name", "ts":"2021-05-21T03:10:20.958450"}`
func main() {
user := new(User)
json.Unmarshal([]byte(data), &user)
fmt.Printf("%v\n", user)
}
Run Code Online (Sandbox Code Playgroud)
time.Time我成功地从 my 中获得了有效值,time.Parse()但我不太明白为什么*st = Time(t)会给出如此奇怪的值?
目前上面的打印结果是:
&{Name {958450000 63757163420 <nil>}}
Run Code Online (Sandbox Code Playgroud)
但我想更类似于:
&{Name 2021-05-21 03:10:20.95845 +0000 UTC}
Run Code Online (Sandbox Code Playgroud)
我在这里误解了什么?
与 time.Time 相反,您的类型没有实现fmt.Stringer,因此 fmt.Print* 函数别无选择,只能使用其默认格式化逻辑,在本例中是打印包含在中的基础 time.Time 值的字段大括号。
添加一个 String 方法,该方法委托给您的类型 time.Time.String 以获得所需的行为:
func (t Time) String() string {
return time.Time(t).String()
}
Run Code Online (Sandbox Code Playgroud)
https://go.dev/play/p/5PwOwa49B5X
或者,将时间类型更改为嵌入 time.Time。这将自动提升 String 方法以及所有其他方法(例如 Marshal* 方法):
type Time struct {
time.Time
}
func (st *Time) UnmarshalJSON(b []byte) error {
// ...
st.Time = t // simple assignment without type conversion
return nil
}
Run Code Online (Sandbox Code Playgroud)
https://go.dev/play/p/0H5qyCO22gu
另外,您永远不应该手动解析 JSON。strings.Trim(string(b), "\"")不足以完全解码 JSON 字符串值。始终使用 json.Unmarshal。您可以使用 time.ParseInLocation 进行简化。
func (st *Time) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
t, err := time.ParseInLocation("2006-01-02T15:04:05", s, time.UTC)
if err != nil {
return err
}
// ...
}
Run Code Online (Sandbox Code Playgroud)