How to check whether current local time is DST? - go

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?

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.

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.

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

Related

How to parse time using a specific timezone

I am to get a time struct from a string. I am using the function time.ParseTime() with the layout "2006-01-02 15:04".
When I execute the function with any valid time string I get a time struct pointing to that time stamp but it is in UTC.
How can I change it to a different time zone? To be clear I want the same timestamp but with a different time zone. I don't want to convert between timezones; I just want to get the same time object but not in UTC.
Use time.ParseInLocation to parse time in a given Location when there's no time zone given. time.Local is your local time zone, pass that in as your Location.
package main
import (
"fmt"
"time"
)
func main() {
// This will honor the given time zone.
// 2012-07-09 05:02:00 +0000 CEST
const formWithZone = "Jan 2, 2006 at 3:04pm (MST)"
t, _ := time.ParseInLocation(formWithZone, "Jul 9, 2012 at 5:02am (CEST)", time.Local)
fmt.Println(t)
// Lacking a time zone, it will use your local time zone.
// Mine is PDT: 2012-07-09 05:02:00 -0700 PDT
const formWithoutZone = "Jan 2, 2006 at 3:04pm"
t, _ = time.ParseInLocation(formWithoutZone, "Jul 9, 2012 at 5:02am", time.Local)
fmt.Println(t)
}

How to load EST timezone properly with the correct daylight saving time UTC shift?

How to load EST timezone properly with the correct daylight saving time UTC shift?
package main
import (
"log"
"time"
)
func main() {
log.SetFlags(log.Lshortfile | log.LstdFlags)
const newYorkTimeZone = "EST"
newYorkLoc, err := time.LoadLocation(newYorkTimeZone)
if err != nil {
log.Printf("error: %+v\n", err)
return
}
ny := time.Now().In(newYorkLoc)
log.Println("ny", ny)
log.Println("utc", ny.UTC())
}
prints:
go run main.go
2021/03/16 19:12:54 main.go:17: ny 2021-03-16 11:12:54.472058 -0500 EST
2021/03/16 19:12:54 main.go:18: utc 2021-03-16 16:12:54.472058 +0000 UTC
So it gives 5 hours time shift with UTC. But I expect it to be 4 hours because today (March 16 2021) NY time zone difference with UTC is 4 hours according to google.
"EST" is Eastern Standard Time, standard meaning "not daylight saving time". Use location instead. That takes into account the daylight savings based on that location. In this case, use the location "America/New_York".

How to add or sub UTC offset value in current time

How can I add or subtract UTC offset (Another time location) value in my current time in GoLang. I tried this link but no use (example)
Example
My input is "UTC+7". I don't know the location. Now I'm in India.
Now I'm getting India (IST) time. Ex: 2019-07-23T15:23:08, Here I need to add UTC+7 in IST. It's possible?
Use time.LoadLocation() to get location information of particular timezone. Then use the .In() method of time object, to convert the current time into expected timezone.
Example:
now := time.Now()
fmt.Println("My place", now)
// 2019-07-23 18:14:23.6036439 +0700 +07
locSingapore, _ := time.LoadLocation("Asia/Singapore")
nowInSingapore := now.In(locSingapore)
fmt.Println("Singapore", nowInSingapore)
// 2019-07-23 19:14:23.6036439 +0800
locLondon, _ := time.LoadLocation("Europe/London")
nowInLondon := now.In(locLondon)
fmt.Println("London", nowInLondon)
// 2019-07-23 12:14:23.6036439 +0100 BST
Explanations:
From code above we can see that time.Now() timezone is +7, it's because I live in West Indonesia.
But nowInSingapore timezone is +8, it's because the now object are adjusted into singapore timezone.
And the last one, nowInLondon is showing another different timezone, +1.
And if we compare all of those time, it's essentially same time.
18:14:23 WIB (GMT +7) == 19:14:23 GMT +8 == 12:14:23 BST (GMT +1)
I Solved the issue.
now := time.Now()
fmt.Println("now:", now.Format("2006-01-02T15:04:05"))
UTC_String_Value := "UTC+7"
UTC_Split_Value := strings.Split(UTC_String_Value, "+")
count, err := strconv.Atoi(UTC_Split_Value [1])
if err != nil {
fmt.Println(err)
}
resp := now.Add(time.Duration(-count) * time.Hour).Format("2006-01-02T15:04:05")
//Subract the utc offset value 7 (hours)
fmt.Println("now:", now.Format("2006-01-02T15:04:05"))
fmt.Println("resp:", resp)
Output
now: 2019-07-24T11:25:17
resp: 2019-07-24T04:25:17

IST time zone error in time package go golang

I need to convert any given time zone in RFC3339 format to system time in RFC3339 format.But for few time zone like IST it is throwing the error and the time is still in UTC.
For conversion which function service as better? time.parse or time.In.
I tried to convert the UTC to IST but it failed.
package main
import (
"fmt"
"time"
)
func main() {
//now time
now := time.Now()
fmt.Println("now ", now)
zone, _ := now.Zone()
fmt.Println("zone->", zone)
ll, llerr := time.LoadLocation(zone)
fmt.Println("Load Location", ll, llerr)
// Convert the given time to system based time zone
t, err := time.ParseInLocation(time.RFC3339, "2017-04-25T23:03:00Z", ll)
fmt.Println("t - parsein", t)
fmt.Println("err - parsein", err)
//fmt.Println("t2 - parse", t.In(ll))
}
Error : unknown time zone IST
Expected: Need to convert any time zone to system time zone.
You can't load Indian IST time zone by that name because the name "IST" is ambiguous. It could mean India, Ireland, Israel, etc. time zones, which have different zone offsets and rules. For details, see Why is time.Parse not using the timezone?
If IST is your local zone, the time.Local variable will denote that time zone. If you have a time.Time, you can "switch" to another zone using Time.In(), also Time.Local() returns the time in your local zone.
Of course this code would "break" when ran in another zone. To make sure it behaves the same everywhere, load the Indian IST zone explicitly like this:
loc, err := time.LoadLocation("Asia/Kolkata")
if err != nil {
panic(err)
}
fmt.Println(time.Now())
fmt.Println(time.Now().In(loc))
On the Go Playground it will output:
2009-11-10 23:00:00 +0000 UTC m=+0.000000001
2009-11-11 04:30:00 +0530 IST

How to use time.Parse to parse hh:mm format in Go

I am importing a lot of fields of the format:
09:02 AM
10:02 AM
12:30 PM
04:10 PM
04:50 PM
05:30 PM
I would like to convert the fields into something I can do arithmetic on. For example, do a count down to when the event Occurs. Thus, saving the field in microseconds... or even seconds.
I have been trying to get the time.Parse to work... no joy.
fmt.Println(time.Parse("hh:mm", m.Feed.Entry[i].GsxA100Time.T))
returns...
0001-01-01 00:00:00 +0000 UTC parsing time "07:50 PM" as "hh:mm": cannot parse "07:50 PM" as "hh:mm"
any suggestions?
The layout string for time.Parse does not handle the "hh:mm" format. In your case, the layout string would rather be "03:04 PM" as you can see in the documentation.
To get a time.Duration after parsing the string, you can substract your time with a reference time, in your case I would assume "12:00 AM".
Working example:
package main
import (
"fmt"
"time"
)
func main() {
ref, _ := time.Parse("03:04 PM", "12:00 AM")
t, err := time.Parse("03:04 PM", "11:22 PM")
if err != nil {
panic(err)
}
fmt.Println(t.Sub(ref).Seconds())
}
Output:
84120
Playground
Did you read the documentation of time.Parse? In the very beginning it says:
The layout defines the format by showing how the reference time,
defined to be Mon Jan 2 15:04:05 -0700 MST 2006 would be interpreted
if it were the value
In the beginning of the package documentation there are more details about the layout string. Note that you can omit some of the fields (in your case days, years and timezeone) and those will then always get zero value.
So fmt.Println(time.Parse("3:04 PM", "07:50 PM")) should work.
If you'll check again the documentation about time's Parse method you'll find the fact that Go's approach of parsing the time is totally different than the one that you used to work with in other programming languages. To provide the Parse function the layout of the time that you want to parse you need to transform one specific date (which is Mon Jan 2 15:04:05 -0700 MST 2006) into the layout that you're aiming for. In your case that would be "03:04 PM".
The full code: fmt.Println(time.Parse("03:04 PM", m.Feed.Entry[i].GsxA100Time.T))
Just in case anyone is working with epoch times can use this,
func convert (in int64) string {
u := time.Unix(in/1000, in%1000)
ampm := "AM"
if u.Hour()/12 ==1 { ampm = "PM" }
th := u.Hour()%12
hh := strconv.Itoa(th)
if th < 10 { hh = "0" + hh }
tm := u.Minute()
mm := strconv.Itoa(tm)
if tm < 10 { mm = "0" + mm }
return hh + ":" + mm + " " + ampm
}

Resources