如何在另一个时区获取等效时间。

huangapple go评论76阅读模式
英文:

How to get equivalent time in another timezone

问题

我正在尝试比较来自不同时区的两个时间,并判断其中一个是否在另一个之前。在Go语言中,你可以这样做:

layout := "2006-01-02 15:04 MST"
sfTime, _ := time.Parse(layout, "2017-03-01 12:00 PDT")
nyTime, _ := time.Parse(layout, "2017-03-01 12:00 EDT")

fmt.Printf("这两个时间相等吗?%v\n", sfTime.Equal(nyTime))

这将打印出:

这两个时间相等吗?true

即使你将它们设置为相同的时区,这只会改变时区,而不会改变HH:mm的值。如果你想要比较不考虑时区的时间,可以将它们转换为UTC时区:

layout := "2006-01-02 15:04 MST"
sfTime, _ := time.Parse(layout, "2017-03-01 12:00 PDT")
nyTime, _ := time.Parse(layout, "2017-03-01 12:00 EDT")

// 将时区设置为UTC
utcLocation, _ := time.LoadLocation("UTC")
sfTime = sfTime.In(utcLocation)
nyTime = nyTime.In(utcLocation)

// 这两个时间应该不相等
fmt.Printf("这两个时间还相等吗?%v\n", sfTime.Equal(nyTime))
fmt.Printf("纽约时间:%v\n", nyTime)

这将打印出:

这两个时间还相等吗?false
纽约时间:2017-03-01 12:00:00 +0000 UTC

你可以在这里查看示例代码的运行结果。

英文:

I'm trying to compare two times from different timezones, and see whether one is before the other. How would I do this in Go?

Note: Basically I would like sfTime.Before(nyTime) == true, but my example below would have sfTime.Before(nyTime) == false. Suggestions on how to make this happen would be great.


For example, in this code...

layout := "2006-01-02 15:04 MST"
sfTime, _ := time.Parse(layout, "2017-03-01 12:00 PDT")
nyTime, _ := time.Parse(layout, "2017-03-01 12:00 EDT")

fmt.Printf("Are these times equal? %v\n", sfTime.Equal(nyTime))

This prints:

> Are these times equal? true

Playground link here.

Unintuitively, even if you set them to be the same timezone, this only changes the timezone, but not the HH:mm value.

layout := "2006-01-02 15:04 MST"
sfTime, _ := time.Parse(layout, "2017-03-01 12:00 PDT")
nyTime, _ := time.Parse(layout, "2017-03-01 12:00 EDT")

// Set timezone to UTC
utcLocation, _ := time.LoadLocation("UTC")
sfTime = sfTime.In(utcLocation)
nyTime = nyTime.In(utcLocation)

// Timezones should not be equal, but they are
fmt.Printf("Are these times still equal? %v\n", sfTime.Equal(nyTime))
fmt.Printf("The New York Time: %v\n", nyTime)

Prints

> Are these times still equal? true
>
> The New York Time: 2017-03-01 12:00:00 +0000 UTC

Playground link.

答案1

得分: 7

不要在Go Playground中使用时间计算,它在一个带有虚假时间的沙盒中运行:

关于Playground的说明:
Go Playground是一个运行在golang.org服务器上的网络服务。
该服务接收一个Go程序,编译、链接并在沙盒中运行该程序,然后返回输出结果。

Playground有一些限制条件适用于可以在其中运行的程序。

在Playground中,时间从2009年11月10日23:00:00 UTC开始(决定这个日期的重要性是读者的练习)。这样做可以通过给程序提供确定性输出来更容易地缓存程序。

此外,Go Playground中的所有时间都使用UTC时区,不使用IANA时区数据库。

例如,对于以下程序:

package main

import (
	"fmt"
	"time"
)

func main() {
	layout := "2006-01-02 15:04 MST"
	sfTime, err := time.Parse(layout, "2017-03-01 12:00 PDT")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(sfTime, sfTime.UTC())
	nyTime, err := time.Parse(layout, "2017-03-01 12:00 EDT")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(nyTime, nyTime.UTC())
	fmt.Printf("这些时间相等吗?%v\n", sfTime.Equal(nyTime))
}

在Go Playground中的输出结果是:

2017-03-01 12:00:00 +0000 PDT 2017-03-01 12:00:00 +0000 UTC
2017-03-01 12:00:00 +0000 EDT 2017-03-01 12:00:00 +0000 UTC
这些时间相等吗?true

要获得正确的输出,请使用Go gc或gccgo编译器运行程序:

$ go run equal.go
2017-03-01 12:00:00 +0000 PDT 2017-03-01 12:00:00 +0000 UTC
2017-03-01 11:00:00 -0500 EST 2017-03-01 16:00:00 +0000 UTC
这些时间相等吗?false

使用Go gc或gccgo编译器运行后,sfTime.Before(nyTime) == true

package main

import (
	"fmt"
	"time"
)

func main() {
	layout := "2006-01-02 15:04 MST"
	sfTime, err := time.Parse(layout, "2017-03-01 12:00 PDT")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(sfTime, sfTime.UTC())
	nyTime, err := time.Parse(layout, "2017-03-01 12:00 EDT")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(nyTime, nyTime.UTC())
	fmt.Printf("SF时间在NY时间之前吗?%v\n", sfTime.Before(nyTime))
}

输出结果为:

$ go run before.go
2017-03-01 12:00:00 +0000 PDT 2017-03-01 12:00:00 +0000 UTC
2017-03-01 11:00:00 -0500 EST 2017-03-01 16:00:00 +0000 UTC
SF时间在NY时间之前吗?true

Go的time包中的比较方法(EqualBeforeAfter)比较的是UTC值。

英文:

Don't use the Go Playground for time calculations. It runs in a sandbox with a fake time:

> About the Playground
>
> The Go Playground is a web service that runs on golang.org's servers.
> The service receives a Go program, compiles, links, and runs the
> program inside a sandbox, then returns the output.
>
> There are limitations to the programs that can be run in the
> playground.
>
> In the playground the time begins at 2009-11-10 23:00:00 UTC
> (determining the significance of this date is an exercise for the
> reader). This makes it easier to cache programs by giving them
> deterministic output.

Also, all times in the Go Playground use the UTC time zone. The Go Playground doesn't use the IANA Time Zone Database.

For example, for this program,

package main

import (
	"fmt"
	"time"
)

func main() {
	layout := "2006-01-02 15:04 MST"
	sfTime, err := time.Parse(layout, "2017-03-01 12:00 PDT")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(sfTime, sfTime.UTC())
	nyTime, err := time.Parse(layout, "2017-03-01 12:00 EDT")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(nyTime, nyTime.UTC())
	fmt.Printf("Are these times equal? %v\n", sfTime.Equal(nyTime))
}

Output from the Go Playground is:

2017-03-01 12:00:00 +0000 PDT 2017-03-01 12:00:00 +0000 UTC
2017-03-01 12:00:00 +0000 EDT 2017-03-01 12:00:00 +0000 UTC
Are these times equal? true

For the correct output, run the program using the Go gc or gccgo compiler:

$ go run equal.go
2017-03-01 12:00:00 +0000 PDT 2017-03-01 12:00:00 +0000 UTC
2017-03-01 11:00:00 -0500 EST 2017-03-01 16:00:00 +0000 UTC
Are these times equal? false

Using the Go gc or gccgo compiler then sfTime.Before(nyTime) == true:

package main

import (
	"fmt"
	"time"
)

func main() {
	layout := "2006-01-02 15:04 MST"
	sfTime, err := time.Parse(layout, "2017-03-01 12:00 PDT")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(sfTime, sfTime.UTC())
	nyTime, err := time.Parse(layout, "2017-03-01 12:00 EDT")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(nyTime, nyTime.UTC())
	fmt.Printf("Is the SF time before the NY time? %v\n", sfTime.Before(nyTime))
}

Output:

$ go run before.go
2017-03-01 12:00:00 +0000 PDT 2017-03-01 12:00:00 +0000 UTC
2017-03-01 11:00:00 -0500 EST 2017-03-01 16:00:00 +0000 UTC
Is the SF time before the NY time? true

The Go time package comparison methods (Equal, Before, and After) compare UTC values.

答案2

得分: 4

我认为这是play.golang.org的一个错误,在我的本地机器上运行时,它返回这些时间相等吗?false这些时间仍然相等吗?false

根据文档,这是预期的行为(返回false):

// Equal报告t和u是否表示相同的时间点。

// 即使两个时间处于不同的位置,它们也可以相等。

// 例如,6:00 +0200 CEST和4:00 UTC是相等的。

你尝试在本地运行过吗?Playground的时间设置为固定的瞬间,所以可能与此有关。

英文:

I think this is a bug with play.golang.org, when I run it on my local machine it returns Are these times equal? false and Are these times still equal? false.

According to the docs this is the expected behaviour (returning false):

> // Equal reports whether t and u represent the same time instant.
>
> // Two times can be equal even if they are in different locations.
>
> // For example, 6:00 +0200 CEST and 4:00 UTC are Equal.

Have you tried running it locally? The playground's time is set to a fixed instant so it may somehow be related to that.

答案3

得分: 3

你的例子按预期工作,Equal比较时间点。如果你想确保时区也相等,可以这样做:t1.Equal(t2) && t1.Location().String() == t2.Location().String()

根据文档的说明:

每个Time对象都有一个关联的Location,在计算时间的表示形式(例如在Format、Hour和Year方法中)时会使用该Location。方法Local、UTC和In返回具有特定位置的Time对象。通过这种方式更改位置只会更改表示形式,而不会更改所表示的时间点,因此不会影响前面描述的计算

因此,据我理解,无论你使用time.Parse("... PDT")time.Parse("... EDT")还是sfTime.In(time.UTC),你始终得到相同的时间点,相同的自1970年以来的秒数,因此在这些Time值上调用EqualBeforeAfter将返回相同的结果,无论Location如何。

更新:我只想补充一下所选择的答案,这不仅适用于Playground,原始的例子在我的机器上也是同样的行为,如果你看一下peterSO对PDT时间的输出,你会发现它仍然被解析为UTC。这种行为在Parse文档的最后一段中有描述(我强调的部分)。

当解析带有时区缩写(如MST)的时间时,如果当前位置的时区缩写具有定义的偏移量,则使用该偏移量。无论位置如何,都将识别时区缩写"UTC"为UTC。**如果时区缩写未知,Parse将记录时间为位于给定时区缩写和零偏移量的虚构位置。**这种选择意味着可以无损地解析和重新格式化此类时间,但表示中使用的确切时间点将因实际时区偏移而异。为避免此类问题,请使用使用数字时区偏移的时间布局,或者使用ParseInLocation。

这里有一个使用ParseInLocation和数字时区偏移的示例:https://play.golang.org/p/vY0muIvk5d

英文:

Your examples are working as intended, Equal comparse an instant in time. If you want to make sure timezones are equal as well you can do something like t1.Equal(t2) && t1.Location().String() == t2.Location().String()

From the docs with added emphasis:

> Each Time has associated with it a Location, consulted when computing
> the presentation form of the time, such as in the Format, Hour, and
> Year methods. The methods Local, UTC, and In return a Time with a
> specific location. Changing the location in this way changes only the
> presentation; it does not change the instant in time
being denoted and
> therefore does not affect the computations described in earlier
> paragraphs.

<strike>So, as far as I understand, whether you do time.Parse(&quot;... PDT&quot;), time.Parse(&quot;... EDT&quot;), or sfTime.In(time.UTC) you always get the same time instant, the same number of seconds since 1970 and therefore calling Equal, Before, and After on those Time values will return the same result, whatever the Location.</strike>

Update: I would just like to add to the chosen answer, that this is not Playground specific, the original examples behave the same way on my machine and if you look at peterSO's output of the PDT time you can see it's still parsed as UTC. This behaviour is described in the last paragraph of Parse's documentation. (emphasis mine)

> 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.

Here's an example using ParseInLocation and numeric timezone offsets: https://play.golang.org/p/vY0muIvk5d

huangapple
  • 本文由 发表于 2017年3月22日 07:25:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/42940065.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定