Golang中如何从JSON读取时间数据

Golang中如何从JSON读取时间数据 我正在尝试从JSON中解析时间。有人能解释一下为什么这些时间不相等吗?

https://play.golang.org/p/uypxBiOhQGw

3 回复

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.

希望这能有所帮助。另请参阅:

在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))
}

关键问题分析:

  1. 时区差异json.Unmarshal解析时间时,如果JSON中的时间包含时区信息(如"Z"表示UTC),Go会正确解析为UTC时间。但直接使用time.Parse时,默认使用本地时区。

  2. 解决方案:使用time.ParseInLocation指定时区:

// 指定时区解析
localTime, _ := time.ParseInLocation(time.RFC3339, "2023-10-05T14:30:00Z", time.UTC)
fmt.Println("指定UTC解析:", localTime)
  1. 自定义时间格式:如果需要特殊格式,可以实现自定义的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)
}
  1. 时间比较的正确方式:使用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()方法可以正确比较时间的实际值。

回到顶部