I'm trying to understand why time.AddDate in Go produces unexpected results during the Daylight Saving Time (DST) transition for the America/Santiago time zone in 2024.
Santiago enter DST at 2024-09-08 00:00:00
here is my code
func TestTimezone1(t *testing.T) {
loc, err := time.LoadLocation("America/Santiago")
if err != nil {
panic(err)
}
t1, err := time.ParseInLocation(time.DateTime, "2024-09-07 00:00:00", loc)
if err != nil {
panic(err)
}
fmt.Println(t1.Unix(), t1.Format(time.DateTime))
t2 := t1.AddDate(0, 0, 1)
fmt.Println(t2.Unix(), t2.Format(time.DateTime), t2.Unix()-t1.Unix())
t3 := t2.AddDate(0, 0, 1)
fmt.Println(t3.Unix(), t3.Format(time.DateTime), t3.Unix()-t2.Unix())
t4 := t1.AddDate(0, 0, 2)
fmt.Println(t4.Unix(), t4.Format(time.DateTime), t4.Unix()-t3.Unix())
}
I Got result
=== RUN TestTimezone1
1725681600 2024-09-07 00:00:00
1725764400 2024-09-07 23:00:00 82800
1725847200 2024-09-08 23:00:00 82800
1725850800 2024-09-09 00:00:00 3600
--- PASS: TestTimezone1 (0.00s)
but I expect
1725681600 2024-09-07 00:00:00
1725768000 2024-09-08 01:00:00 86400
1725850800 2024-09-09 00:00:00 82800
1725850800 2024-09-09 00:00:00 0
and why t3 != t4 ?
TL;DR : you hit this weirdness because running .AddDate(0,0,1) on the first time.Time object asks for an invalid date-time in this timezone (2024-09-08 00:00:00 does not exist), and because of the way the standard time package in go deals with these non existing date-times.
fact: the date-time2024-09-08 00:00:00 does not exist in the "America/Santiago" timezone -- actually, the whole hour is skipped when switching to summer time, any 2024-09-08 00:mm:ss is an invalid date-time in that timezone.
t.AddDate(...) internally calls time.Date(...) (link to code), and it so happens that the implementation of this function has its own heuristic to dance around non existing date time inputs. Illustration:
a := time.Date(2024, 9, 7, 23, 59, 59, 0, loc_santiago)
b := time.Date(2024, 9, 8, 0, 0, 0, 0, loc_santiago)
c := time.Date(2024, 9, 8, 0, 59, 59, 0, loc_santiago)
d := time.Date(2024, 9, 8, 1, 0, 0, 0, loc_santiago)
// 2024-09-07 23:59:59 -04
// 2024-09-07 23:00:00 -04 # clock is rolled back one hour ... :/
// 2024-09-07 23:59:59 -04
// 2024-09-08 01:00:00 -03
https://go.dev/play/p/AMLkuk5d79W
So: when you start at 2024-09-07 00:00:00, and then add "1 day", you reach the time.Time described by b in the example above.
I must say I am also surprised by this implementation, I would probably expect to have a heuristic which would generate increasing unix timestamps when parsing increasing date-time strings.
The documentation of both Date() and Time.AddDate() describe the behavior when dealing with ambiguous date-time values, but not really what happens on invalid date-time values.
You could probably open an issue or ask on the golang slack channel for more details.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With