Golang: Get equivalent time in different timezone
I am trying to compare two times with different time zones and see if one is in front of the other. How can I do this in golang?
Note . Basically I would love to sfTime.Before(nyTime) == true
, but my example below would have sfTime.Before(nyTime) == false
. Suggestions on how to do this 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))
Prints:
Are these times equal? true
Unintuitively, even if you set them to the same timezone, this only changes the timezone, not the value HH:mm
.
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)
Printing
Are these times still equal? true
New York time: 2017-03-01 12:00:00 +0000 UTC
source to share
Don't use the Go Playground for timing. He works in a sandbox with a fake time:
Go Playground is a web service that runs on golang.org servers. The service receives a Go program, compiles, links and runs the program inside the sandbox, then returns the result.
There are restrictions on the programs that can be performed in the playground.
On the playground, 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.
In addition, Go uses UTC at all times. Go Playground does not 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))
}
Exiting the 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
Are these times equal? true
For correct output, run the program with the Go compiler gc or 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
Are these times equal? false
Using the Go compiler gc or gccgo, 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
Go's packet comparison methods time
( Equal
, Before
and After
) compare UTC values.
source to share
I think this is a bug from 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
.
As per the docs, this is the expected behavior (returning false):
// Equal messages about whether t and u represent the same time.
// Two times can be equal even if they are in different places.
// For example, 6:00 +0200 CEST and 4:00 UTC are equal.
Have you tried running it locally? The time on the playing court is set to a fixed point in time, so it may somehow be related to that.
source to share
Your examples are working as intended, Equal point-in-time comparison . If you want to make sure the timezones are equal, you can do something liket1.Equal(t2) && t1.Location().String() == t2.Location().String()
From the docs with emphasis:
Each time is associated with it by a location, which is handled by the time representation when calculating, for example, format, hour, and year methods. Local, UTC and In Return methods are the time from a specific location. Changing the location in this way only changes the presentation; it does not change the point in time indicated and therefore does not affect the calculations described in the paragraphs earlier.
So, as far as I understand, whether you are executing time.Parse("... PDT")
, time.Parse("... EDT")
or sfTime.In(time.UTC)
, you always get the same point in time, the same number of seconds since 1970, and therefore call Equal
, Before
and After
on those time values return the same result, regardless of Location
.
Update . I would just like to add to the selected answer that this is not playground specific, the original examples behave the same on my machine and if you look at the peterSO PDT output the time you can see is still treated as UTC. This behavior is described in the last paragraph of the Parse
documentation . (emphasis mine)
When analyzing time with a zone abbreviation such as MST, if the zone abbreviation has a certain offset at the current location, then the offset is used. The zone abbreviation "UTC" is recognized as UTC regardless of location. If the zone abbreviation is not known, Parse records the time as being in a fabricated location with the given zone abbreviation and zero offset. This choice means that such time can be parsed and reformatted with the same layout losslessly, but the exact moment used in the view will be different from the actual zone offset. To avoid such problems, prefers timing layouts that use a numeric zone offset or use ParseInLocation.
Here's an example using ParseInLocation
and numerical timezone offsets: https://play.golang.org/p/vY0muIvk5d
source to share