From b669f2e8ac20dafcfd01b1c4245d067d695254cc Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 30 Sep 2014 19:05:41 +0300 Subject: [PATCH] using extrenal lib for next date --- engine/action_timing.go | 24 +++++++++++++ engine/actions_test.go | 12 +++---- engine/loader_csv_test.go | 26 +++++++------- engine/rateinterval.go | 68 ++++++++++++++++++++++++++++++++++++ engine/rateinterval_test.go | 56 ++++++++++++++++++++++++++++- hard_update_external_libs.py | 1 + update_external_libs.sh | 1 + 7 files changed, 168 insertions(+), 20 deletions(-) diff --git a/engine/action_timing.go b/engine/action_timing.go index d7064cb16..6d19f9a1b 100644 --- a/engine/action_timing.go +++ b/engine/action_timing.go @@ -25,6 +25,7 @@ import ( "time" "github.com/cgrates/cgrates/utils" + "github.com/gorhill/cronexpr" ) const ( @@ -46,6 +47,29 @@ type ActionTiming struct { type ActionPlan []*ActionTiming func (at *ActionTiming) GetNextStartTime(now time.Time) (t time.Time) { + if !at.stCache.IsZero() { + return at.stCache + } + i := at.Timing + if i == nil || i.Timing == 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) + } + at.stCache = cronexpr.MustParse(i.Timing.CronString()).Next(now) + 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 } diff --git a/engine/actions_test.go b/engine/actions_test.go index 7c9847705..65fc71a24 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -69,9 +69,9 @@ func TestActionTimingOnlyHour(t *testing.T) { } func TestActionTimingHourYear(t *testing.T) { - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{2012}, StartTime: "10:01:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{2022}, StartTime: "10:01:00"}}} st := at.GetNextStartTime(referenceDate) - expected := time.Date(2012, 1, 1, 10, 1, 0, 0, time.Local) + expected := time.Date(2022, 1, 1, 10, 1, 0, 0, time.Local) if !st.Equal(expected) { t.Errorf("Expected %v was %v", expected, st) } @@ -245,9 +245,9 @@ func TestActionTimingOnlyYears(t *testing.T) { } func TestActionTimingPast(t *testing.T) { - at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{2013}}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{2023}}}} st := at.GetNextStartTime(referenceDate) - expected := time.Date(2013, 1, 1, 0, 0, 0, 0, time.Local) + expected := time.Date(2023, 1, 1, 0, 0, 0, 0, time.Local) if !st.Equal(expected) { t.Errorf("Expected %v was %v", expected, st) } @@ -411,7 +411,7 @@ func TestActionTimingLogFunction(t *testing.T) { func TestActionTimingPriotityListSortByWeight(t *testing.T) { at1 := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ - Years: utils.Years{2100}, + Years: utils.Years{2020}, Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, MonthDays: utils.MonthDays{1}, StartTime: "00:00:00", @@ -420,7 +420,7 @@ func TestActionTimingPriotityListSortByWeight(t *testing.T) { }} at2 := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ - Years: utils.Years{2100}, + Years: utils.Years{2020}, Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, MonthDays: utils.MonthDays{2}, StartTime: "00:00:00", diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index c31e82a91..45cc649ad 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -532,28 +532,28 @@ func TestLoadRatingPlans(t *testing.T) { expected := &RatingPlan{ Id: "STANDARD", Timings: map[string]*RITiming{ - "14ae6e41": &RITiming{ + "4c954a4f": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{1, 2, 3, 4, 5}, StartTime: "00:00:00", }, - "9a6f8e32": &RITiming{ + "4d593287": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{1, 2, 3, 4, 5}, StartTime: "18:00:00", }, - "7181e535": &RITiming{ + "a60bfb13": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{time.Saturday, time.Sunday}, StartTime: "00:00:00", }, - "96c78ff5": &RITiming{ + "30eab300": &RITiming{ Years: utils.Years{}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, @@ -618,48 +618,48 @@ func TestLoadRatingPlans(t *testing.T) { DestinationRates: map[string]RPRateList{ "GERMANY": []*RPRate{ &RPRate{ - Timing: "14ae6e41", + Timing: "4c954a4f", Rating: "822a5aef", Weight: 10, }, &RPRate{ - Timing: "9a6f8e32", + Timing: "4d593287", Rating: "4a25c533", Weight: 10, }, &RPRate{ - Timing: "7181e535", + Timing: "a60bfb13", Rating: "4a25c533", Weight: 10, }, }, "GERMANY_O2": []*RPRate{ &RPRate{ - Timing: "14ae6e41", + Timing: "4c954a4f", Rating: "4a25c533", Weight: 10, }, &RPRate{ - Timing: "9a6f8e32", + Timing: "4d593287", Rating: "b05c5f6b", Weight: 10, }, &RPRate{ - Timing: "7181e535", + Timing: "a60bfb13", Rating: "b05c5f6b", Weight: 10, }, }, "GERMANY_PREMIUM": []*RPRate{ &RPRate{ - Timing: "14ae6e41", + Timing: "4c954a4f", Rating: "4a25c533", Weight: 10, }, }, "URG": []*RPRate{ &RPRate{ - Timing: "96c78ff5", + Timing: "30eab300", Rating: "9f49ef8e", Weight: 20, }, @@ -667,7 +667,7 @@ func TestLoadRatingPlans(t *testing.T) { }, } if !reflect.DeepEqual(rplan, expected) { - t.Errorf("Error loading destination rate timing: %+v", rplan.DestinationRates["URG"][0]) + t.Errorf("Error loading destination rate timing: %+v", rplan.DestinationRates["GERMANY_O2"][0]) } } diff --git a/engine/rateinterval.go b/engine/rateinterval.go index 535fb73f6..7b0f8b176 100644 --- a/engine/rateinterval.go +++ b/engine/rateinterval.go @@ -45,6 +45,74 @@ type RITiming struct { MonthDays utils.MonthDays WeekDays utils.WeekDays StartTime, EndTime string // ##:##:## format + cronString string +} + +func (rit *RITiming) CronString() string { + if rit.cronString != "" { + return rit.cronString + } + var sec, min, hour, monthday, month, weekday, year string + if len(rit.StartTime) == 0 { + hour, min, sec = "*", "*", "*" + } else { + hms := strings.Split(rit.StartTime, ":") + if len(hms) != 3 { + hour, min, sec = "*", "*", "*" + } + hour, min, sec = hms[0], hms[1], hms[2] + if strings.HasPrefix(hour, "0") { + hour = hour[1:] + } + if strings.HasPrefix(min, "0") { + min = min[1:] + } + if strings.HasPrefix(sec, "0") { + sec = sec[1:] + } + } + if len(rit.MonthDays) == 0 { + monthday = "*" + } else { + for i, md := range rit.MonthDays { + if i > 0 { + monthday += "," + } + monthday += strconv.Itoa(md) + } + } + if len(rit.Months) == 0 { + month = "*" + } else { + for i, md := range rit.Months { + if i > 0 { + month += "," + } + month += strconv.Itoa(int(md)) + } + } + if len(rit.WeekDays) == 0 { + weekday = "*" + } else { + for i, md := range rit.WeekDays { + if i > 0 { + weekday += "," + } + weekday += strconv.Itoa(int(md)) + } + } + if len(rit.Years) == 0 { + year = "*" + } else { + for i, md := range rit.Years { + if i > 0 { + year += "," + } + year += strconv.Itoa(int(md)) + } + } + rit.cronString = fmt.Sprintf("%s %s %s %s %s %s %s", sec, min, hour, monthday, month, weekday, year) + return rit.cronString } func (rit *RITiming) Stringify() string { diff --git a/engine/rateinterval_test.go b/engine/rateinterval_test.go index de24999a3..980fb2f20 100644 --- a/engine/rateinterval_test.go +++ b/engine/rateinterval_test.go @@ -19,9 +19,10 @@ along with this program. If not, see package engine import ( - "github.com/cgrates/cgrates/utils" "testing" "time" + + "github.com/cgrates/cgrates/utils" ) func TestRateIntervalSimpleContains(t *testing.T) { @@ -283,6 +284,59 @@ func TestRateStrigyfy(t *testing.T) { } } +func TestRateIntervalCronAll(t *testing.T) { + rit := &RITiming{ + Years: utils.Years{2012}, + Months: utils.Months{time.February}, + MonthDays: utils.MonthDays{1}, + WeekDays: []time.Weekday{time.Sunday}, + StartTime: "14:30:00", + } + expected := "0 30 14 1 2 0 2012" + cron := rit.CronString() + if cron != expected { + t.Errorf("Expected %s was %s", expected, cron) + } +} + +func TestRateIntervalCronMultiple(t *testing.T) { + rit := &RITiming{ + Years: utils.Years{2012, 2014}, + Months: utils.Months{time.February, time.January}, + MonthDays: utils.MonthDays{15, 16}, + WeekDays: []time.Weekday{time.Sunday, time.Monday}, + StartTime: "14:30:00", + } + expected := "0 30 14 15,16 2,1 0,1 2012,2014" + cron := rit.CronString() + + if cron != expected { + t.Errorf("Expected %s was %s", expected, cron) + } +} + +func TestRateIntervalCronStar(t *testing.T) { + rit := &RITiming{ + StartTime: "*:30:00", + } + expected := "0 30 * * * * *" + cron := rit.CronString() + + if cron != expected { + t.Errorf("Expected %s was %s", expected, cron) + } +} + +func TestRateIntervalCronEmpty(t *testing.T) { + rit := &RITiming{} + expected := "* * * * * * *" + cron := rit.CronString() + + if cron != expected { + t.Errorf("Expected %s was %s", expected, cron) + } +} + /*********************************Benchmarks**************************************/ func BenchmarkRateIntervalContainsDate(b *testing.B) { diff --git a/hard_update_external_libs.py b/hard_update_external_libs.py index bb59c3f72..c281908fd 100755 --- a/hard_update_external_libs.py +++ b/hard_update_external_libs.py @@ -14,6 +14,7 @@ libs = ('code.google.com/p/goconf/conf', 'github.com/hoisie/redis' 'github.com/howeyc/fsnotify', 'github.com/jinzhu/gorm', + 'github.com/gorhill/cronexpr', ) if __name__ == "__main__": diff --git a/update_external_libs.sh b/update_external_libs.sh index 95453330c..74ef16f04 100755 --- a/update_external_libs.sh +++ b/update_external_libs.sh @@ -11,3 +11,4 @@ go get -u -v github.com/howeyc/fsnotify go get -u -v github.com/cgrates/liner go get -u -v github.com/cgrates/rpcclient go get -u -v github.com/jinzhu/gorm +go get -u -v github.com/gorhill/cronexpr