parsing - 为什么 time.Parse 不使用时区?

标签 parsing go time timezone

为什么 time.Parse 不使用时区信息?它应该针对不同的时区返回不同的时间。

代码

package main

import (
    "fmt"
    "time"
)

func main() {
    t, err := time.Parse("2006-01-02 MST", "2018-05-11 IST")
    if err != nil {
        return
    }
    t2, err := time.Parse("2006-01-02 MST", "2018-05-11 UTC")
    if err != nil {
        return
    }
    fmt.Println(t.Unix())
    fmt.Println(t2.Unix())
}

输出:

1525996800
1525996800

最佳答案

对问题本身的一些解释:

这 2 个时间戳 2018-05-11 IST2018-05-11 UTC 不指定同一时刻,因为 IST 与 UTC 具有不同的偏移量:印度标准时间 (IST) 比协调世界时 (UTC) 早 5:30。

Time.Unix()返回自引用时间(UTC 时间 1970 年 1 月 1 日)以来经过的秒数。这意味着输出应该不同!

在 PlayGround 上运行你的代码确实给出了错误的结果(link)。

这是一个与时区相关的问题。如果您尝试加载 IST 时区:

loc, err := time.LoadLocation("IST")
fmt.Println(loc, err)

输出:

UTC cannot find IST in zip file /usr/local/go/lib/time/zoneinfo.zip

而“IST”不被支持的原因是因为它有歧义。它可能表示印度、爱尔兰、以色列等时区,它们具有不同的时区偏移量和规则。

time.Parse() 的文档指出

If the zone abbreviation is unknown, Parse records the time as being in a fabricated location with the given zone abbreviation and a zero offset.

因此 parse.Parse() 返回的 time.time 将像 UTC 时区一样具有 0 偏移量,因此它会产生相同的“unix 时间” (Time.Unix() 将返回相同的值)。

但是在本地(使用我的 CET)时区运行它会给出不同的正确结果:

t, err := time.Parse("2006-01-02 MST", "2018-05-11 CET")
if err != nil {
    panic(err)
}
t2, err := time.Parse("2006-01-02 MST", "2018-05-11 UTC")
if err != nil {
    panic(err)
}
fmt.Println(t)
fmt.Println(t2)

fmt.Println(t.Unix())
fmt.Println(t2.Unix())

输出:

2018-05-11 01:00:00 +0200 CEST
2018-05-11 00:00:00 +0000 UTC
1525993200
1525996800

time.Parse() 的文档关于用时区缩写解析时间有这样的说法:

When parsing a time with a zone abbreviation like MST, if the zone abbreviation has a defined offset in the current location, then that offset is used. The zone abbreviation "UTC" is recognized as UTC regardless of location. If the zone abbreviation is unknown, Parse records the time as being in a fabricated location with the given zone abbreviation and a zero offset. This choice means that such a time can be parsed and reformatted with the same layout losslessly, but the exact instant used in the representation will differ by the actual zone offset. To avoid such problems, prefer time layouts that use a numeric zone offset, or use ParseInLocation.

文档建议使用带有数字区域偏移量的布局进行解析,如下所示:

t, err := time.Parse("2006-01-02 -0700", "2018-05-11 +0530")
if err != nil {
    panic(err)
}

然后输出(在 Go Playground 上试试):

2018-05-11 00:00:00 +0530 +0530
2018-05-11 00:00:00 +0000 UTC
1525977000
1525996800

另一种选择是使用 time.FixedZone()自己构造 IST,并使用 time.ParseInLocation() ,传递我们的手册 IST 位置:

ist := time.FixedZone("IST", 330*60) // +5:30
t, err := time.ParseInLocation("2006-01-02 MST", "2018-05-11 IST", ist)

输出将是(在 Go Playground 上尝试):

2018-05-11 00:00:00 +0530 IST
2018-05-11 00:00:00 +0000 UTC
1525977000
1525996800

另一种选择是通过加尔各答市加载印度 IST 区域:

loc, err := time.LoadLocation("Asia/Kolkata")
if err != nil {
    panic(err)
}

这将产生相同的输出。在 Go Playground 上试用.

关于parsing - 为什么 time.Parse 不使用时区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50287664/

相关文章:

go - 选择和上下文。上下文完成 channel

mysql - Excel 使用 MSQuery 将时间格式更改为日期时间

ios - 当设备在 iOS 7 上进入休眠状态时,clock_get_time/mach_absolute_time 停止更新

java - Android XML 解析错误 - "Couldn' t 打开 .../directory/container.xml"

c++ - 如何在 C++ 中使用简单的递归下降解析器解析基本算术(例如 "5+5")?

html - 监控新用户

java - 如何在java中仅显示日期时间组合的时间部分

r - R中反波兰符号的求值

r - 动态解析离散的 x 轴标签

unit-testing - 测试非不透明错误值