How to get equivalent time in another timezone
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.
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.
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.
So, as far as I understand, whether you do time.Parse("... PDT")
, time.Parse("... EDT")
, 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
.
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