dqm4977
dqm4977
2017-03-21 23:25

Golang:获取其他时区的等效时间

已采纳

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

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
", 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
", sfTime.Equal(nyTime))
fmt.Printf("The New York Time: %v
", nyTime)

Prints

Are these times still equal? true

The New York Time: 2017-03-01 12:00:00 +0000 UTC

Playground link.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

3条回答

  • doufen5175 doufen5175 4年前

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

    点赞 评论 复制链接分享
  • doucongmishang2385 doucongmishang2385 4年前

    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

    点赞 评论 复制链接分享
  • douzi6992 douzi6992 4年前

    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.

    点赞 评论 复制链接分享

为你推荐