diff --git a/apier/v1/apier.go b/apier/v1/apier.go index 8eaa625bd..c6e0954b6 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -809,6 +809,15 @@ func checkDefaultTiming(tStr string) (rTm *engine.RITiming, isDefault bool) { StartTime: startTime, EndTime: "", }, true + case utils.MetaMonthEnd: + return &engine.RITiming{ + Years: utils.Years{}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{-1}, + WeekDays: utils.WeekDays{}, + StartTime: startTime, + EndTime: "", + }, true case utils.MetaYearly: return &engine.RITiming{ Years: utils.Years{}, diff --git a/engine/action_plan.go b/engine/action_plan.go index c7e118a48..391faf94e 100644 --- a/engine/action_plan.go +++ b/engine/action_plan.go @@ -131,157 +131,6 @@ func (at *ActionTiming) GetNextStartTime(now time.Time) (t time.Time) { return at.stCache } -// To be deleted after the above solution proves reliable -func (at *ActionTiming) GetNextStartTimeOld(now time.Time) (t time.Time) { - if !at.stCache.IsZero() { - return at.stCache - } - i := at.Timing - if i == nil { - return - } - // Normalize - if i.Timing.StartTime == "" { - i.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(i.Timing.Months) > 0 && len(i.Timing.MonthDays) == 0 { - i.Timing.MonthDays = append(i.Timing.MonthDays, 1) - } - y, m, d := now.Date() - z, _ := now.Zone() - if i.Timing.StartTime != utils.ASAP { - l := fmt.Sprintf("%d-%d-%d %s %s", y, m, d, i.Timing.StartTime, z) - var err error - t, err = time.Parse(FORMAT, l) - if err != nil { - utils.Logger.Err(fmt.Sprintf("Cannot parse action plan's StartTime %v", l)) - at.stCache = t - return - } - if now.After(t) || now.Equal(t) { // Set it to next day this time - t = t.AddDate(0, 0, 1) - } - } - // weekdays - if i.Timing.WeekDays != nil && len(i.Timing.WeekDays) > 0 { - i.Timing.WeekDays.Sort() - if t.IsZero() { - t = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, now.Location()) - } - for j := 0; j < 8; j++ { - n := t.AddDate(0, 0, j) - for _, wd := range i.Timing.WeekDays { - if n.Weekday() == wd && (n.Equal(now) || n.After(now)) { - at.stCache = n - t = n - return - } - } - } - } - // monthdays - if i.Timing.MonthDays != nil && len(i.Timing.MonthDays) > 0 { - i.Timing.MonthDays.Sort() - year := t.Year() - month := t - x := sort.SearchInts(i.Timing.MonthDays, t.Day()) - d = i.Timing.MonthDays[0] - if x < len(i.Timing.MonthDays) { - if i.Timing.MonthDays[x] == t.Day() { - if t.Equal(now) || t.After(now) { - goto MONTHS - } - if x+1 < len(i.Timing.MonthDays) { // today was found in the list, jump to the next grater day - d = i.Timing.MonthDays[x+1] - } else { // jump to next month - //not using now to make sure the next month has the the 1 date - //(if today is 31) next month may not have it - tmp := time.Date(year, month.Month(), 1, 0, 0, 0, 0, time.Local) - month = tmp.AddDate(0, 1, 0) - } - } else { // today was not found in the list, x is the first greater day - d = i.Timing.MonthDays[x] - } - } - h, m, s := t.Clock() - t = time.Date(month.Year(), month.Month(), d, h, m, s, 0, time.Local) - } -MONTHS: - if i.Timing.Months != nil && len(i.Timing.Months) > 0 { - i.Timing.Months.Sort() - year := t.Year() - x := sort.Search(len(i.Timing.Months), func(x int) bool { return i.Timing.Months[x] >= t.Month() }) - m = i.Timing.Months[0] - if x < len(i.Timing.Months) { - if i.Timing.Months[x] == t.Month() { - if t.Equal(now) || t.After(now) { - goto YEARS - } - if x+1 < len(i.Timing.Months) { // this month was found in the list so jump to next available month - m = i.Timing.Months[x+1] - // reset the monthday - t = time.Date(t.Year(), t.Month(), i.Timing.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) - } else { // jump to next year - //not using now to make sure the next year has the the 1 date - //(if today is 31) next month may not have it - tmp := time.Date(year, 1, 1, 0, 0, 0, 0, time.Local) - year = tmp.AddDate(1, 0, 0).Year() - } - } else { // this month was not found in the list, x is the first greater month - m = i.Timing.Months[x] - // reset the monthday - t = time.Date(t.Year(), t.Month(), i.Timing.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) - } - } - h, min, s := t.Clock() - t = time.Date(year, m, t.Day(), h, min, s, 0, time.Local) - } else { - if now.After(t) { - t = t.AddDate(0, 1, 0) - } - } -YEARS: - if i.Timing.Years != nil && len(i.Timing.Years) > 0 { - i.Timing.Years.Sort() - x := sort.Search(len(i.Timing.Years), func(x int) bool { return i.Timing.Years[x] >= t.Year() }) - y = i.Timing.Years[0] - if x < len(i.Timing.Years) { - if i.Timing.Years[x] == now.Year() { - if t.Equal(now) || t.After(now) { - h, m, s := t.Clock() - t = time.Date(now.Year(), t.Month(), t.Day(), h, m, s, 0, time.Local) - at.stCache = t - return - } - if x+1 < len(i.Timing.Years) { // this year was found in the list so jump to next available year - y = i.Timing.Years[x+1] - // reset the month - if i.Timing.Months != nil { - t = time.Date(t.Year(), i.Timing.Months[0], t.Day(), t.Hour(), t.Minute(), t.Second(), 0, t.Location()) - } - // reset the monthday - t = time.Date(t.Year(), t.Month(), i.Timing.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) - } - } else { // this year was not found in the list, x is the first greater year - y = i.Timing.Years[x] - // reset the month/monthday - t = time.Date(t.Year(), i.Timing.Months[0], i.Timing.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) - } - } - h, min, s := t.Clock() - t = time.Date(y, t.Month(), t.Day(), h, min, s, 0, time.Local) - } else { - if now.After(t) { - t = t.AddDate(1, 0, 0) - } - } - at.stCache = t - return -} - func (at *ActionTiming) ResetStartTimeCache() { at.stCache = time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC) } diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 4a9e5b5d4..a3988dec2 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -185,7 +185,7 @@ func TestLoadReverseDestinations(t *testing.T) { } func TestLoadTimimgs(t *testing.T) { - if len(csvr.timings) != 12 { + if len(csvr.timings) != 13 { t.Error("Failed to load timings: ", csvr.timings) } timing := csvr.timings["WORKDAYS_00"] diff --git a/engine/rateinterval.go b/engine/rateinterval.go index 650393a9f..e03056f67 100644 --- a/engine/rateinterval.go +++ b/engine/rateinterval.go @@ -118,6 +118,9 @@ func (rit *RITiming) CronString() string { year += strconv.Itoa(int(md)) } } + if monthday == "-1" { // in case we receive -1 we send to cron special character L ( Last ) + monthday = "L" + } rit.cronString = fmt.Sprintf("%s %s %s %s %s %s %s", sec, min, hour, monthday, month, weekday, year) return rit.cronString } diff --git a/engine/tpreader.go b/engine/tpreader.go index 9b39c791b..a358c8a57 100644 --- a/engine/tpreader.go +++ b/engine/tpreader.go @@ -2613,6 +2613,15 @@ func (tpr *TpReader) addDefaultTimings() { StartTime: startTime, EndTime: "", } + tpr.timings[utils.MetaMonthEnd] = &utils.TPTiming{ + ID: utils.MetaMonthEnd, + Years: utils.Years{}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{-1}, + WeekDays: utils.WeekDays{}, + StartTime: startTime, + EndTime: "", + } tpr.timings[utils.MetaYearly] = &utils.TPTiming{ ID: utils.MetaYearly, Years: utils.Years{}, diff --git a/utils/consts.go b/utils/consts.go index aae5f1af1..1b5070418 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -769,6 +769,7 @@ const ( MetaPartial = "*partial" MetaBusy = "*busy" MetaQueue = "*queue" + MetaMonthEnd = "*month_end" ) // Migrator Action