为什么time.Parse没有使用时区?

Pra*_*jan 3 time timezone parsing go

为什么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())
}
Run Code Online (Sandbox Code Playgroud)

输出:

1525996800
1525996800
Run Code Online (Sandbox Code Playgroud)

icz*_*cza 7

对问题本身的一些解释:

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

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

在PlayGround上运行代码确实会产生错误的结果(链接).

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

loc, err := time.LoadLocation("IST")
fmt.Println(loc, err)
Run Code Online (Sandbox Code Playgroud)

输出:

UTC cannot find IST in zip file /usr/local/go/lib/time/zoneinfo.zip
Run Code Online (Sandbox Code Playgroud)

并且不支持"IST"的原因是因为它含糊不清.它可能意味着印度,爱尔兰,以色列等时区,它们具有不同的区域偏移和规则.

并记录time.Parse()状态

如果区域缩写未知,则Parse将时间记录为具有给定区域缩写和零偏移的制造位置.

因此,time.time返回的parse.Parse()将具有与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())
Run Code Online (Sandbox Code Playgroud)

输出:

2018-05-11 01:00:00 +0200 CEST
2018-05-11 00:00:00 +0000 UTC
1525993200
1525996800
Run Code Online (Sandbox Code Playgroud)

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

在使用区域缩写(如MST)解析时间时,如果区域缩写在当前位置具有已定义的偏移量,则使用该偏移量.无论位置如何,区域缩写"UTC"都被识别为UTC.如果区域缩写未知,则Parse将时间记录为具有给定区域缩写和零偏移的制造位置.这种选择意味着可以无损地使用相同的布局解析和重新格式化这样的时间,但是表示中使用的确切时刻将因实际的区域偏移而不同.要避免此类问题,请首选使用数字区域偏移的时间布局,或使用ParseInLocation.

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

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

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

2018-05-11 00:00:00 +0530 +0530
2018-05-11 00:00:00 +0000 UTC
1525977000
1525996800
Run Code Online (Sandbox Code Playgroud)

另一个选择是使用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)
Run Code Online (Sandbox Code Playgroud)

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

2018-05-11 00:00:00 +0530 IST
2018-05-11 00:00:00 +0000 UTC
1525977000
1525996800
Run Code Online (Sandbox Code Playgroud)

  • “IST”是模棱两可的。可能是印度、爱尔兰、以色列,它们都是不同的时区。Go 不可能知道这些是什么意思;但是如果应用程序开发人员这样做,那么您可以使用`time.ParseInLocation()`。 (2认同)