Golang中如何从JSON读取时间数据
Golang中如何从JSON读取时间数据 我正在尝试从JSON中解析时间。有人能解释一下为什么这些时间不相等吗?
将 time.Time 类型定义为新类型,并实现 json.Marshaler 接口。
package main
import (
"encoding/json"
"fmt"
"time"
)
type Time time.Time
func (t Time) String() string {
return time.Time(t).Format("2006-01-02")
}
func (t Time) MarshalJSON() ([]byte, error) {
return []byte("\"" + t.String() + "\""), nil
}
type Info struct {
LastTime Time `json:"lastime"`
}
func main() {
info := &Info{Time(time.Now())}
body, err := json.Marshal(info)
fmt.Printf("%#v\n", info)
fmt.Println(info.LastTime)
fmt.Println(string(body), err)
}
// &main.Info{LastTime:main.Time{wall:0xbab699fc00000000, ext:1, loc:(*time.Location)(0x5affe0)}}
// 2009-11-10
// {"lastime":"2009-11-10"} <nil>
更多关于Golang中如何从JSON读取时间数据的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
时区缩写并非仅对应一个单一的偏移量。在第一个示例中,您指定了时区,这比偏移量(+0200)更为具体。在第二个示例中,您仅从偏移量解析时间,因此它可能是以下任意一种:
| 缩写 | 名称 | 偏移量 |
|---|---|---|
| CAT | 中非时间 | UTC+02 |
| CEST | 中欧夏令时 (参见 HAEC) | UTC+02 |
| EET | 东欧时间 | UTC+02 |
| HAEC | 中欧夏令时的法语名称 | UTC+02 |
| IST | 以色列标准时间 | UTC+02 |
| KALT | 加里宁格勒时间 | UTC+02 |
| MEST | 中欧夏令时 (与 CEST 同区) | UTC+02 |
| SAST | 南非标准时间 | UTC+02 |
| WAST | 西非夏令时 | UTC+02 |
在您的情况下,您知道自己需要的是 CEST,但如果您是从其他来源解析数据,您如何知道呢?当您得到一个 +03:00 的时间时又该怎么办呢?
然而,要解决这个具体问题,我认为您可能正在寻找 Time.In。将此添加到您的 Playground 示例中:
ti2 = ti2.In(zh)
… 输出结果是:
2009/11/10 23:00:00 First time is : 2012-04-23 18:25:43.000000511 +0200 CEST
2009/11/10 23:00:00 Second time is: 2012-04-23 18:25:43.000000511 +0200 CEST
Program exited.
希望这能有所帮助。另请参阅:
- 这条有用的评论 - 其中指出,更复杂的是,这些代码本身并不能保证是唯一的。CEST 是唯一的,但并非所有代码都是。偏移量是一种更可靠的思考方式。
- 时区缩写列表。
- ExampleLoadLocation。
在Go中处理JSON时间解析时,需要特别注意时区问题。根据你提供的代码示例,问题确实出在时区处理上。
package main
import (
"encoding/json"
"fmt"
"time"
)
type Data struct {
Time time.Time `json:"time"`
}
func main() {
// JSON字符串
jsonStr := `{"time": "2023-10-05T14:30:00Z"}`
var data Data
err := json.Unmarshal([]byte(jsonStr), &data)
if err != nil {
fmt.Println("解析错误:", err)
return
}
fmt.Println("解析后的时间:", data.Time)
fmt.Println("UTC时间:", data.Time.UTC())
fmt.Println("本地时间:", data.Time.Local())
// 创建相同时间的time.Time对象
parsedTime, _ := time.Parse(time.RFC3339, "2023-10-05T14:30:00Z")
fmt.Println("直接解析的时间:", parsedTime)
// 比较时间
fmt.Println("是否相等?", data.Time.Equal(parsedTime))
fmt.Println("data.Time:", data.Time.Format(time.RFC3339))
fmt.Println("parsedTime:", parsedTime.Format(time.RFC3339))
}
关键问题分析:
-
时区差异:
json.Unmarshal解析时间时,如果JSON中的时间包含时区信息(如"Z"表示UTC),Go会正确解析为UTC时间。但直接使用time.Parse时,默认使用本地时区。 -
解决方案:使用
time.ParseInLocation指定时区:
// 指定时区解析
localTime, _ := time.ParseInLocation(time.RFC3339, "2023-10-05T14:30:00Z", time.UTC)
fmt.Println("指定UTC解析:", localTime)
- 自定义时间格式:如果需要特殊格式,可以实现自定义的JSON unmarshal:
type CustomTime struct {
time.Time
}
func (ct *CustomTime) UnmarshalJSON(b []byte) error {
s := string(b)
s = s[1 : len(s)-1] // 去除引号
t, err := time.Parse("2006-01-02 15:04:05", s)
if err != nil {
return err
}
ct.Time = t
return nil
}
type Data2 struct {
Time CustomTime `json:"time"`
}
func main() {
jsonStr := `{"time": "2023-10-05 14:30:00"}`
var data Data2
json.Unmarshal([]byte(jsonStr), &data)
fmt.Println("自定义格式时间:", data.Time)
}
- 时间比较的正确方式:使用
time.Equal()而不是==操作符:
t1, _ := time.Parse(time.RFC3339, "2023-10-05T14:30:00Z")
t2, _ := time.Parse(time.RFC3339, "2023-10-05T14:30:00Z")
// 正确比较
fmt.Println("使用Equal:", t1.Equal(t2)) // true
// 可能不正确的比较
fmt.Println("使用==:", t1 == t2) // 可能为false,因为包含时区信息
主要原因是time.Time类型包含时区信息,即使时间值相同,如果时区不同,使用==比较会返回false。使用time.Equal()方法可以正确比较时间的实际值。

