Revise GetNextStartTime method

This commit is contained in:
armirveliaj
2024-11-06 10:34:48 -05:00
committed by Dan Christian Bogos
parent b66e9bb31f
commit fd156c4838
3 changed files with 213 additions and 35 deletions

View File

@@ -117,35 +117,48 @@ func getDayOrEndOfMonth(day int, t1 time.Time) int {
return day
}
func (at *ActionTiming) GetNextStartTime(t1 time.Time) (t time.Time) {
func (at *ActionTiming) GetNextStartTime(refTime time.Time) time.Time {
if !at.stCache.IsZero() {
return at.stCache
}
i := at.Timing
if i == nil || i.Timing == nil {
return
rateIvl := at.Timing
if rateIvl == nil || rateIvl.Timing == nil {
return time.Time{}
}
// Normalize
if i.Timing.StartTime == "" {
i.Timing.StartTime = "00:00:00"
if rateIvl.Timing.StartTime == "" {
rateIvl.Timing.StartTime = "00:00:00"
}
if len(i.Timing.Years) > 0 && len(i.Timing.Months) == 0 {
i.Timing.Months = append(i.Timing.Months, 1)
if len(rateIvl.Timing.Years) > 0 && len(rateIvl.Timing.Months) == 0 {
rateIvl.Timing.Months = append(rateIvl.Timing.Months, 1)
}
if len(i.Timing.Months) > 0 && len(i.Timing.MonthDays) == 0 {
i.Timing.MonthDays = append(i.Timing.MonthDays, 1)
if len(rateIvl.Timing.Months) > 0 && len(rateIvl.Timing.MonthDays) == 0 {
rateIvl.Timing.MonthDays = append(rateIvl.Timing.MonthDays, 1)
}
at.stCache = cronexpr.MustParse(i.Timing.CronString()).Next(t1)
if i.Timing.ID == utils.MetaMonthlyEstimated {
// substract a month from at.stCache only if we skip 2 months
// or we skip a month because mentioned MonthDay is after the last day of the current month
if at.stCache.Month() == t1.Month()+2 ||
(utils.GetEndOfMonth(t1).Day() < at.Timing.Timing.MonthDays[0] &&
at.stCache.Month() == t1.Month()+1) {
lastDay := utils.GetEndOfMonth(at.stCache).Day()
// only change the time if the new one is after t1
if tmp := at.stCache.AddDate(0, 0, -lastDay); tmp.After(t1) {
at.stCache = tmp
at.stCache = cronexpr.MustParse(rateIvl.Timing.CronString()).Next(refTime)
if rateIvl.Timing.ID == utils.MetaMonthlyEstimated {
// When target day doesn't exist in a month, fall back to that month's last day
// instead of skipping to next occurrence.
currentMonth := refTime.Month()
targetMonthDay := rateIvl.Timing.MonthDays[0]
oneMonthSkip := utils.GetEndOfMonth(refTime).Day() < targetMonthDay &&
at.stCache.Month() == currentMonth+1
twoMonthSkip := at.stCache.Month() == currentMonth+2
if oneMonthSkip || twoMonthSkip {
daysToSubtract := utils.GetEndOfMonth(at.stCache).Day()
// When transitioning from Jan to Feb, subtract the
// actual desired day instead of Mar's last day.
// This fixes cases like:
// - Jan 29 -> Mar 29 (should be Feb 28 in non-leap years)
// - Jan 30 -> Mar 30 (should be Feb 28/29)
if currentMonth == time.January {
daysToSubtract = targetMonthDay
}
adjustedTime := at.stCache.AddDate(0, 0, -daysToSubtract)
if adjustedTime.After(refTime) {
at.stCache = adjustedTime
}
}
}

View File

@@ -516,20 +516,19 @@ func TestActionTimingGetNextStartTimesMonthlyEstimated(t *testing.T) {
},
expected: time.Date(2021, 1, 31, 14, 25, 0, 0, time.UTC),
},
// {
// name: "Non-Leap Year: January 29 to Feb 28",
// t1: time.Date(2021, 1, 29, 0, 0, 0, 0, time.UTC),
// at: &ActionTiming{
// Timing: &RateInterval{
// Timing: &RITiming{
// ID: utils.MetaMonthlyEstimated,
// MonthDays: utils.MonthDays{29},
// },
// },
// },
// expected: time.Date(2021, 2, 28, 0, 0, 0, 0, time.UTC),
// },
{
name: "Non-Leap Year: January 29 to Feb 28",
t1: time.Date(2021, 1, 29, 0, 0, 0, 0, time.UTC),
at: &ActionTiming{
Timing: &RateInterval{
Timing: &RITiming{
ID: utils.MetaMonthlyEstimated,
MonthDays: utils.MonthDays{29},
},
},
},
expected: time.Date(2021, 2, 28, 0, 0, 0, 0, time.UTC),
},
{
name: "Non-Leap Year: February 28 to March 28",
t1: time.Date(2021, 2, 28, 0, 0, 0, 0, time.UTC),
@@ -622,6 +621,77 @@ func TestActionTimingGetNextStartTimesMonthlyEstimated(t *testing.T) {
},
expected: time.Date(2021, 9, 30, 0, 0, 0, 0, time.UTC),
},
{
name: "Non-Leap Year: Jan 29 to Feb 28",
t1: time.Date(2021, 1, 29, 0, 0, 0, 0, time.UTC),
at: &ActionTiming{
Timing: &RateInterval{
Timing: &RITiming{
ID: utils.MetaMonthlyEstimated,
MonthDays: utils.MonthDays{29},
StartTime: "00:00:00",
},
},
},
expected: time.Date(2021, 2, 28, 0, 0, 0, 0, time.UTC),
},
{
name: "Leap Year: Jan 30 to Feb 29 ",
t1: time.Date(2020, 1, 30, 0, 0, 0, 0, time.UTC),
at: &ActionTiming{
Timing: &RateInterval{
Timing: &RITiming{
ID: utils.MetaMonthlyEstimated,
MonthDays: utils.MonthDays{30},
StartTime: "00:00:00",
},
},
},
expected: time.Date(2020, 2, 29, 0, 0, 0, 0, time.UTC),
},
{
name: "Non-Leap Year: Jan 30 to Feb 28 ",
t1: time.Date(2021, 1, 30, 0, 0, 0, 0, time.UTC),
at: &ActionTiming{
Timing: &RateInterval{
Timing: &RITiming{
ID: utils.MetaMonthlyEstimated,
MonthDays: utils.MonthDays{30},
StartTime: "00:00:00",
},
},
},
expected: time.Date(2021, 2, 28, 0, 0, 0, 0, time.UTC),
},
{
name: "Non-Leap Year: Jan 15 to Feb 15 ",
t1: time.Date(2021, 1, 15, 0, 0, 0, 0, time.UTC),
at: &ActionTiming{
Timing: &RateInterval{
Timing: &RITiming{
ID: utils.MetaMonthlyEstimated,
MonthDays: utils.MonthDays{15},
StartTime: "00:00:00",
},
},
},
expected: time.Date(2021, 2, 15, 0, 0, 0, 0, time.UTC),
},
{
name: "Jan 14 to Jan 15 ",
t1: time.Date(2021, 1, 14, 0, 0, 0, 0, time.UTC),
at: &ActionTiming{
Timing: &RateInterval{
Timing: &RITiming{
ID: utils.MetaMonthlyEstimated,
MonthDays: utils.MonthDays{15},
StartTime: "00:00:00",
},
},
},
expected: time.Date(2021, 1, 15, 0, 0, 0, 0, time.UTC),
},
}
for _, tt := range tests {