Golang 小坑之 time.Parse 的默认时区

7,923 阅读2分钟

先上代码

准备获得一个我们的双十一的时间 2021-11-11 00:00:00

t, _ := time.Parse("2006-01-02 15:04:05", "2021-11-11 00:00:00")


tStr := t.Format("2006-01-02 15:04:05")
timestamp := t.Unix()
fmt.Println(t, "||", tStr, "||", timestamp)
// 2021-11-11 00:00:00 +0000 UTC || 2021-11-11 00:00:00 || 1636588800

打开时间戳工具 Unix时间戳(Unix timestamp)转换工具 - 站长工具

2021-11-10 at 21.44.png

发现时间戳 1636588800 对应的时间是 2021-11-11 08:00:00,比预期的多了 8 小时。

问题分析

再仔细看一下,打印的 time 里面 2021-11-11 00:00:00 +0000 UTC 是 UTC 的时间。看起来这个 Parse 时间没有考虑时区,当做默认的 +0 时区 UTC 时间来解析了,就造成了实际时间比预期的 +8 小时(在国内机器上执行这段代码)。

为了好理解这里列一下转换关系:

2021-11-11 00:00:00 +0800 CST // 预期时间
2021-11-10 16:00:00 +0000 UTC // 预期时间对应的 UTC 时间

2021-11-11 00:00:00 +0000 UTC // Parse 到的时间
2021-11-11 08:00:00 +0800 CST // Parse 到的时间的等效 CST 时间

解决办法

怎么解决呢?

有两个办法,在 time string 中加上时区信息来解析:

t, _ := time.Parse("2006-01-02 15:04:05  -0700 MST", "2021-11-11 00:00:00 +0800 CST")

tStr := t.Format("2006-01-02 15:04:05")
timestamp := t.Unix()
fmt.Println(t, "||", tStr, "||", timestamp)
// 2021-11-11 00:00:00 +0800 CST || 2021-11-11 00:00:00 || 1636560000

或者使用 time.ParseInLocation 方法:

t, _ := time.ParseInLocation("2006-01-02 15:04:05", "2021-11-11 00:00:00", time.Local)
tStr := t.Format("2006-01-02 15:04:05")
timestamp := t.Unix()
fmt.Println(t, "||", tStr, "||", timestamp)
// 2021-11-11 00:00:00 +0800 CST || 2021-11-11 00:00:00 || 1636560000

这里直接使用了 time.Local,会根据系统配置来,如果需要自定义的话,也可以自己设置,比如:

location, err := time.LoadLocation("Asia/Shanghai")

这里得到的 location 和 time.Local 类型相同。