XZen
XZen

Reputation: 445

How to check whether current local time is DST?

In Ruby, for example, there's the Time#dst? function, which returns true in the case it is daylight saving time. Is there a Go standard library API call to do the same?

Upvotes: 12

Views: 4466

Answers (3)

colm.anseo
colm.anseo

Reputation: 22027

In August 2021 go 1.17 was released which now adds the time.Time method IsDST:

IsDST reports whether the time in the configured location is in Daylight Savings Time.

Upvotes: 7

peterSO
peterSO

Reputation: 166529

You can infer the result. For example,

package main

import (
    "fmt"
    "time"
)

// isTimeDST returns true if time t occurs within daylight saving time
// for its time zone.
func isTimeDST(t time.Time) bool {
    // If the most recent (within the last year) clock change
    // was forward then assume the change was from std to dst.
    hh, mm, _ := t.UTC().Clock()
    tClock := hh*60 + mm
    for m := -1; m > -12; m-- {
        // assume dst lasts for least one month
        hh, mm, _ := t.AddDate(0, m, 0).UTC().Clock()
        clock := hh*60 + mm
        if clock != tClock {
            if clock > tClock {
                // std to dst
                return true
            }
            // dst to std
            return false
        }
    }
    // assume no dst
    return false
}

func main() {
    pstLoc, err := time.LoadLocation("America/Los_Angeles")
    if err != nil {
        fmt.Println(err)
        return
    }

    utc := time.Date(2018, 10, 29, 14, 0, 0, 0, time.UTC)
    fmt.Println(utc, utc.Location(), ": DST", isTimeDST(utc))
    local := utc.In(time.Local)
    fmt.Println(local, local.Location(), ": DST", isTimeDST(local))
    pst := utc.In(pstLoc)
    fmt.Println(pst, pst.Location(), ": DST", isTimeDST(pst))

    utc = utc.AddDate(0, 3, 0)
    fmt.Println(utc, utc.Location(), ": DST", isTimeDST(utc))
    local = utc.In(time.Local)
    fmt.Println(local, local.Location(), ": DST", isTimeDST(local))
    pst = utc.In(pstLoc)
    fmt.Println(pst, pst.Location(), ": DST", isTimeDST(pst))
}

Output:

2018-10-29 14:00:00 +0000 UTC UTC : DST false
2018-10-29 10:00:00 -0400 EDT Local : DST true
2018-10-29 07:00:00 -0700 PDT America/Los_Angeles : DST true
2019-01-29 14:00:00 +0000 UTC UTC : DST false
2019-01-29 09:00:00 -0500 EST Local : DST false
2019-01-29 06:00:00 -0800 PST America/Los_Angeles : DST false

Upvotes: 3

Dan N
Dan N

Reputation: 167

The Location api doesn't export the DST value of the timezone. This was brought up in the golang-nuts forum several years ago. One suggestion is to compare the January 1 timezone offset to the July 1 timezone offset. A working solution of this was posted using this method. One caveat is that goplay has the wrong local time, so it doesn't correctly report the information if you run it there. You can run it locally to verify that it does work.

Another way would be to use reflection via the reflect package. A solution that I wrote to do this is available here. There are a lot of problems with this method.

Edit: Really it should probably use cacheZone but does a linear search of the zones to find one that matches. This can lead to errors because some timezones share name and offset. The correct way would be to look at cacheZone and use that if it is set. Otherwise, you'll need to either look at zoneTrans or at least look at how lookup(int64) is implemented.

Upvotes: 3

Related Questions