diff --git a/rrule.go b/rrule.go index 4a49f3e..44a71a9 100644 --- a/rrule.go +++ b/rrule.go @@ -666,12 +666,20 @@ func (iterator *rIterator) generate() { continue } i := day.Int - dateYear, dateMonth, dateDay := iterator.ii.firstyday.AddDate(0, 0, i).Date() + date := iterator.ii.firstyday.AddDate(0, 0, i) + dateYear, dateMonth, dateDay := date.Date() for _, timeTemp := range iterator.timeset { tempHour, tempMinute, tempSecond := timeTemp.Clock() - res := time.Date(dateYear, dateMonth, dateDay, - tempHour, tempMinute, tempSecond, - timeTemp.Nanosecond(), timeTemp.Location()) + + var res time.Time + if r.freq < HOURLY { + res = time.Date(dateYear, dateMonth, dateDay, + tempHour, tempMinute, tempSecond, + timeTemp.Nanosecond(), timeTemp.Location()) + } else { + res = date.Add(time.Duration(tempHour)*time.Hour + time.Duration(tempMinute)*time.Minute + time.Duration(tempSecond)*time.Second) + } + if !r.until.IsZero() && res.After(r.until) { r.len = iterator.total iterator.finished = true diff --git a/rrule_test.go b/rrule_test.go index a49f09f..f807b6c 100644 --- a/rrule_test.go +++ b/rrule_test.go @@ -1,5 +1,6 @@ // 2017-2022, Teambition. All rights reserved. + package rrule import ( @@ -3926,6 +3927,90 @@ func TestRuleChangeDTStartTimezoneRespected(t *testing.T) { } } +func TestDST_HourlyDSTStart(t *testing.T) { + sydLoc, _ := time.LoadLocation("Australia/Sydney") + r, _ := NewRRule(ROption{Freq: HOURLY, Interval: 1, Count: 3, + Dtstart: time.Date(2022, 10, 2, 1, 0, 0, 0, sydLoc), + }) + got := r.All() + want := []string{ + "2022-10-02 01:00:00 +1000 AEST", + "2022-10-02 03:00:00 +1100 AEDT", + "2022-10-02 04:00:00 +1100 AEDT", + } + for i, g := range got { + if g.String() != want[i] { + t.Errorf("got: %v, want: %v", g, want[i]) + } + } + var utcTimes []time.Time + for _, dt := range got { + utcTimes = append(utcTimes, dt.UTC()) + } + want = []string{ + "2022-10-01 15:00:00 +0000 UTC", + "2022-10-01 16:00:00 +0000 UTC", + "2022-10-01 17:00:00 +0000 UTC", + } + + for i, g := range utcTimes { + if g.String() != want[i] { + t.Errorf("got: %v, want: %v", g, want[i]) + } + } +} + +func TestDST_HourlyDSTEnd(t *testing.T) { + sydLoc, _ := time.LoadLocation("Australia/Sydney") + r, _ := NewRRule(ROption{Freq: HOURLY, Interval: 1, Count: 3, + Dtstart: time.Date(2023, 4, 2, 1, 0, 0, 0, sydLoc), + }) + got := r.All() + want := []string{ + "2023-04-02 01:00:00 +1100 AEDT", + "2023-04-02 02:00:00 +1100 AEDT", + "2023-04-02 02:00:00 +1000 AEST", + } + for i, g := range got { + if g.String() != want[i] { + t.Errorf("got: %v, want: %v", g, want[i]) + } + } + + var utcTimes []time.Time + for _, dt := range got { + utcTimes = append(utcTimes, dt.UTC()) + } + want = []string{ + "2023-04-01 14:00:00 +0000 UTC", + "2023-04-01 15:00:00 +0000 UTC", + "2023-04-01 16:00:00 +0000 UTC", + } + for i, g := range utcTimes { + if g.String() != want[i] { + t.Errorf("got: %v, want: %v", g, want[i]) + } + } +} + + +func TestDailyDST(t *testing.T) { + sydney, _ := time.LoadLocation("Australia/Sydney") + r, _ := NewRRule(ROption{ + Freq: DAILY, + Count: 3, + Dtstart: time.Date(2023, 4, 1, 9, 0, 0, 0, sydney), + }) + want := []time.Time{ + time.Date(2023, 4, 1, 9, 0, 0, 0, sydney), + time.Date(2023, 4, 2, 9, 0, 0, 0, sydney), + time.Date(2023, 4, 3, 9, 0, 0, 0, sydney), + } + value := r.All() + if !timesEqual(value, want) { + t.Errorf("get %v, want %v", value, want) + } +} func BenchmarkIterator(b *testing.B) { type testCase struct { Name string