为什么time.Parse不使用时区? [英] Why is time.Parse not using the timezone?

查看:76
本文介绍了为什么time.Parse不使用时区?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么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

解决方案

对问题本身的一些解释:

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

Time.Unix() 返回直到瞬间的经过的秒数,自参考时间(世界标准时间1970年1月1日)起经过的时间.这意味着输出应该不同!

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

这是与时区有关的问题.如果您尝试加载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() 的文档指出

如果区域缩写未知,则Parse记录时间,该时间位于指定的区域缩写和零偏移的虚构位置.

因此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() 的文档中所说的是解析带区域缩写的时间:

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

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

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

然后输出(在游乐场上尝试):

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)

输出将是(在游乐场上尝试):

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

将产生相同的输出.在游乐场上进行尝试.

Why is time.Parse not using timezone information? It should return different time for different timezones.

Code

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

Output:

1525996800
1525996800

解决方案

Some explanation to the question itself:

These 2 timestamps 2018-05-11 IST and 2018-05-11 UTC do not designate the same time instant because IST has a different offset than UTC: India Standard Time (IST) is 5:30 hours ahead of Coordinated Universal Time (UTC).

And Time.Unix() returns the elapsed seconds up to the time instant, elapsed since the reference time (January 1, 1970 UTC). Which implies the output should be different!

Running your code on the PlayGround indeed gives wrong result (link).

And it is a timezone related issue. If you try to load the IST timezone:

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

Output:

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

And the reason why "IST" is not supported is because it is ambiguous. It could mean India, Ireland, Israel, etc. time zones, which have different zone offsets and rules.

And documentation of time.Parse() states that

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.

So the time.time returned by parse.Parse() will have 0 offset just like the UTC zone, hence it will result in the same "unix time" (Time.Unix() will return the same value).

But running it locally (with my CET) timezone gives different, correct result:

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())

Output:

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

Documentation of time.Parse() has this to say about parsing a time with zone abbreviation:

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.

Documentation suggests to parse with a layout with numeric zone offset, like this:

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

Then output (try it on the Go Playground):

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

Another option is to use time.FixedZone() to construct IST yourself, and use time.ParseInLocation(), passing our manual IST location:

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

Output will be (try it on the Go Playground):

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

Yet another option is to load Indian IST zone by Kolkata city:

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

Which will produce the same output. Try it on the Go Playground.

这篇关于为什么time.Parse不使用时区?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆