diff --git a/timespans/activationperiod.go b/timespans/activationperiod.go index bf9ed47ce..7a42b9932 100644 --- a/timespans/activationperiod.go +++ b/timespans/activationperiod.go @@ -1,9 +1,9 @@ -package timespans +package timespans import ( - "time" - "strings" "strconv" + "strings" + "time" ) const LAYOUT = "2006-01-02T15:04:05Z07:00" @@ -28,16 +28,16 @@ func (ap *ActivationPeriod) AddInterval(is ...*Interval) { /* Serializes the objects for the storage. */ -func (ap *ActivationPeriod) store() (result string){ +func (ap *ActivationPeriod) store() (result string) { result += ap.ActivationTime.Format(LAYOUT) + ";" var is string - for _,i := range ap.Intervals { + for _, i := range ap.Intervals { is = strconv.Itoa(int(i.Month)) + "|" is += strconv.Itoa(i.MonthDay) + "|" for _, wd := range i.WeekDays { is += strconv.Itoa(int(wd)) + "," } - is = strings.TrimRight(is, ",") + "|" + is = strings.TrimRight(is, ",") + "|" is += i.StartTime + "|" is += i.EndTime + "|" is += strconv.FormatFloat(i.Ponder, 'f', -1, 64) + "|" @@ -45,33 +45,33 @@ func (ap *ActivationPeriod) store() (result string){ is += strconv.FormatFloat(i.Price, 'f', -1, 64) + "|" is += strconv.FormatFloat(i.BillingUnit, 'f', -1, 64) result += is + ";" - } - return + } + return } /* De-serializes the objects for the storage. */ -func (ap *ActivationPeriod) restore(input string) { - elements := strings.Split(input, ";") +func (ap *ActivationPeriod) restore(input string) { + elements := strings.Split(input, ";") ap.ActivationTime, _ = time.Parse(LAYOUT, elements[0]) - for _, is := range elements[1:len(elements) - 1]{ + for _, is := range elements[1 : len(elements)-1] { i := &Interval{} - ise := strings.Split(is, "|") + ise := strings.Split(is, "|") month, _ := strconv.Atoi(ise[0]) i.Month = time.Month(month) - i.MonthDay, _ = strconv.Atoi(ise[1]) - for _,d := range strings.Split(ise[2], ","){ - wd,_ := strconv.Atoi(d) + i.MonthDay, _ = strconv.Atoi(ise[1]) + for _, d := range strings.Split(ise[2], ",") { + wd, _ := strconv.Atoi(d) i.WeekDays = append(i.WeekDays, time.Weekday(wd)) } i.StartTime = ise[3] - i.EndTime = ise[4] - i.Ponder, _ = strconv.ParseFloat(ise[5], 64) + i.EndTime = ise[4] + i.Ponder, _ = strconv.ParseFloat(ise[5], 64) i.ConnectFee, _ = strconv.ParseFloat(ise[6], 64) i.Price, _ = strconv.ParseFloat(ise[7], 64) i.BillingUnit, _ = strconv.ParseFloat(ise[8], 64) - + ap.Intervals = append(ap.Intervals, i) - } + } } diff --git a/timespans/activationperiod_test.go b/timespans/activationperiod_test.go index acfd96699..796dd227c 100644 --- a/timespans/activationperiod_test.go +++ b/timespans/activationperiod_test.go @@ -6,13 +6,13 @@ import ( //"log" ) -func TestApStoreRestore(t *testing.T) { +func TestApStoreRestore(t *testing.T) { d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) i := &Interval{Month: time.February, MonthDay: 1, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", - EndTime: "15:00:00"} + EndTime: "15:00:00"} ap := ActivationPeriod{ActivationTime: d} ap.AddInterval(i) result := ap.store() @@ -27,37 +27,37 @@ func TestApStoreRestore(t *testing.T) { } i1 := ap1.Intervals[0] if i1.Month != i.Month { - t.Errorf("Expected %q was %q", i.Month, i1.Month) + t.Errorf("Expected %q was %q", i.Month, i1.Month) } if i1.MonthDay != i.MonthDay { - t.Errorf("Expected %q was %q", i.MonthDay, i1.MonthDay) + t.Errorf("Expected %q was %q", i.MonthDay, i1.MonthDay) } - for j,wd := range i1.WeekDays { + for j, wd := range i1.WeekDays { if wd != i1.WeekDays[j] { - t.Errorf("Expected %q was %q", i.StartTime, i1.StartTime) - } + t.Errorf("Expected %q was %q", i.StartTime, i1.StartTime) + } } if i1.StartTime != i.StartTime { - t.Errorf("Expected %q was %q", i.StartTime, i1.StartTime) + t.Errorf("Expected %q was %q", i.StartTime, i1.StartTime) } if i1.EndTime != i.EndTime { - t.Errorf("Expected %q was %q", i.EndTime, i1.EndTime) + t.Errorf("Expected %q was %q", i.EndTime, i1.EndTime) } if i1.Ponder != i.Ponder { - t.Errorf("Expected %q was %q", i.Ponder, i1.Ponder) + t.Errorf("Expected %q was %q", i.Ponder, i1.Ponder) } if i1.ConnectFee != i.ConnectFee { - t.Errorf("Expected %q was %q", i.ConnectFee, i1.ConnectFee) + t.Errorf("Expected %q was %q", i.ConnectFee, i1.ConnectFee) } if i1.Price != i.Price { - t.Errorf("Expected %q was %q", i.Price, i1.Price) + t.Errorf("Expected %q was %q", i.Price, i1.Price) } if i1.BillingUnit != i.BillingUnit { - t.Errorf("Expected %q was %q", i.BillingUnit, i1.BillingUnit) + t.Errorf("Expected %q was %q", i.BillingUnit, i1.BillingUnit) } } -func BenchmarkRestore(b *testing.B) { +func BenchmarkRestore(b *testing.B) { ap1 := ActivationPeriod{} for i := 0; i < b.N; i++ { ap1.restore("1328106601;2|1|3,4|14:30:00|15:00:00|0|0|0|0;") diff --git a/timespans/calldesc.go b/timespans/calldesc.go index d180650e7..0d59c45ff 100644 --- a/timespans/calldesc.go +++ b/timespans/calldesc.go @@ -2,8 +2,9 @@ package timespans import ( "fmt" - "time" "strings" + "time" + //"log" ) /* @@ -33,7 +34,7 @@ func (cd *CallDescriptor) EncodeValues() (result string) { for _, ap := range cd.ActivationPeriods { result += ap.store() + "\n" } - return + return } /* @@ -41,7 +42,7 @@ Restores the activation periods list from a storage string. */ func (cd *CallDescriptor) decodeValues(v string) { for _, aps := range strings.Split(v, "\n") { - if(len(aps)>0){ + if len(aps) > 0 { ap := &ActivationPeriod{} ap.restore(aps) cd.ActivationPeriods = append(cd.ActivationPeriods, ap) @@ -57,46 +58,59 @@ func (cd *CallDescriptor) GetKey() string { } /* -Finds the intervals applicable to the call descriptior. +Finds the activation periods applicable to the call descriptior. */ -func (cd *CallDescriptor) getActiveIntervals() (is []*Interval) { - now := time.Now() - // add a second in the future to be able to pick the active timestamp - // from the very second it becomes active - sec, _ := time.ParseDuration("1s") - now.Add(sec) +func (cd *CallDescriptor) getActivePeriods() (is []*ActivationPeriod) { + is = make([]*ActivationPeriod, 1) // make room for the initial activation period bestTime := time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC) for _, ap := range cd.ActivationPeriods { t := ap.ActivationTime - if t.After(bestTime) && t.Before(now) { + if t.After(bestTime) && t.Before(cd.TimeStart) { bestTime = t - is = ap.Intervals + is[0] = ap + } + if t.After(cd.TimeStart) && t.Before(cd.TimeEnd) { + is = append(is, ap) } } return } /* -Splits the call timespan into sub time spans accordin to the received intervals. +Splits the call timespan into sub time spans accordin to the activation periods intervals. */ -func (cd *CallDescriptor) splitInTimeSpans(intervals []*Interval) (timespans []*TimeSpan) { +func (cd *CallDescriptor) splitInTimeSpans(aps []*ActivationPeriod) (timespans []*TimeSpan) { ts1 := &TimeSpan{TimeStart: cd.TimeStart, TimeEnd: cd.TimeEnd} - timespans = append(timespans, ts1) - for _, interval := range intervals { + ts1.ActivationPeriod = aps[0] // first activation period starts before the timespan + + timespans = append(timespans, ts1) + + for _, ap := range aps { for _, ts := range timespans { - newTs := interval.Split(ts) + newTs := ts.SplitByActivationPeriod(ap) if newTs != nil { timespans = append(timespans, newTs) break } } } + + for i := 0; i < len(timespans); i++ { + ts := timespans[i] + for _, interval := range ts.ActivationPeriod.Intervals { + newTs := ts.SplitByInterval(interval) + if newTs != nil { + newTs.ActivationPeriod = ts.ActivationPeriod + timespans = append(timespans, newTs) + } + } + } return } /* Creates a CallCost structure with the cost nformation calculated for the received CallDescriptor. - */ +*/ func (cd *CallDescriptor) GetCost(sg StorageGetter) (result *CallCost, err error) { key := cd.GetKey() @@ -104,11 +118,11 @@ func (cd *CallDescriptor) GetCost(sg StorageGetter) (result *CallCost, err error cd.decodeValues(values) - intervals := cd.getActiveIntervals() - timespans := cd.splitInTimeSpans(intervals) + periods := cd.getActivePeriods() + timespans := cd.splitInTimeSpans(periods) cost := 0.0 - for _, ts := range timespans { + for _, ts := range timespans { cost += ts.GetCost() } cc := &CallCost{TOR: cd.TOR, diff --git a/timespans/calldesc_test.go b/timespans/calldesc_test.go index 9e3054aa1..e84aca010 100644 --- a/timespans/calldesc_test.go +++ b/timespans/calldesc_test.go @@ -18,8 +18,8 @@ func TestKyotoSplitSpans(t *testing.T) { cd.decodeValues(values) - intervals := cd.getActiveIntervals() - timespans := cd.splitInTimeSpans(intervals) + periods := cd.getActivePeriods() + timespans := cd.splitInTimeSpans(periods) if len(timespans) != 2 { t.Error("Wrong number of timespans: ", len(timespans)) } @@ -37,14 +37,13 @@ func TestRedisSplitSpans(t *testing.T) { cd.decodeValues(values) - intervals := cd.getActiveIntervals() - timespans := cd.splitInTimeSpans(intervals) + periods := cd.getActivePeriods() + timespans := cd.splitInTimeSpans(periods) if len(timespans) != 2 { t.Error("Wrong number of timespans: ", len(timespans)) } } - func TestKyotoGetCost(t *testing.T) { getter, _ := NewKyotoStorage("test.kch") defer getter.Close() @@ -114,11 +113,14 @@ func BenchmarkSplitting(b *testing.B) { t1 := time.Date(2012, time.February, 02, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 02, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2} + key := cd.GetKey() + values, _ := getter.Get(key) + cd.decodeValues(values) b.StartTimer() for i := 0; i < b.N; i++ { - intervals := cd.getActiveIntervals() - cd.splitInTimeSpans(intervals) + periods := cd.getActivePeriods() + cd.splitInTimeSpans(periods) } } @@ -129,7 +131,7 @@ func BenchmarkKyotoGetting(b *testing.B) { t1 := time.Date(2012, time.February, 02, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 02, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2} b.StartTimer() for i := 0; i < b.N; i++ { getter.Get(cd.GetKey()) @@ -143,7 +145,7 @@ func BenchmarkRedisGetting(b *testing.B) { t1 := time.Date(2012, time.February, 02, 17, 30, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 02, 18, 30, 0, 0, time.UTC) - cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2} + cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2} b.StartTimer() for i := 0; i < b.N; i++ { getter.Get(cd.GetKey()) @@ -158,10 +160,9 @@ func BenchmarkDecoding(b *testing.B) { cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256"} key := cd.GetKey() values, _ := getter.Get(key) - + b.StartTimer() for i := 0; i < b.N; i++ { cd.decodeValues(values) } } - diff --git a/timespans/interval_test.go b/timespans/interval_test.go index bd039adea..8b5c67136 100644 --- a/timespans/interval_test.go +++ b/timespans/interval_test.go @@ -127,130 +127,6 @@ func TestEverything(t *testing.T) { } } -func TestRightMargin(t *testing.T) { - i := &Interval{WeekDays: []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}} - t1 := time.Date(2012, time.February, 3, 23, 45, 0, 0, time.UTC) - t2 := time.Date(2012, time.February, 4, 0, 10, 0, 0, time.UTC) - ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} - oldDuration := ts.GetDuration() - nts := i.Split(ts) - if ts.TimeStart != t1 || ts.TimeEnd != time.Date(2012, time.February, 3, 23, 59, 59, 0, time.UTC) { - t.Error("Incorrect first half", ts) - } - if nts.TimeStart != time.Date(2012, time.February, 3, 23, 59, 59, 0, time.UTC) || nts.TimeEnd != t2 { - t.Error("Incorrect second half", nts) - } - if ts.Interval != i { - t.Error("Interval not attached correctly") - } - - if ts.GetDuration().Seconds() != 15*60-1 || nts.GetDuration().Seconds() != 10*60+1 { - t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), ts.GetDuration().Seconds()) - } - - if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { - t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) - } -} - -func TestRightHourMargin(t *testing.T) { - i := &Interval{WeekDays: []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}, EndTime: "17:59:00"} - t1 := time.Date(2012, time.February, 3, 17, 30, 0, 0, time.UTC) - t2 := time.Date(2012, time.February, 3, 18, 00, 0, 0, time.UTC) - ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} - oldDuration := ts.GetDuration() - nts := i.Split(ts) - if ts.TimeStart != t1 || ts.TimeEnd != time.Date(2012, time.February, 3, 17, 59, 00, 0, time.UTC) { - t.Error("Incorrect first half", ts) - } - if nts.TimeStart != time.Date(2012, time.February, 3, 17, 59, 00, 0, time.UTC) || nts.TimeEnd != t2 { - t.Error("Incorrect second half", nts) - } - if ts.Interval != i { - t.Error("Interval not attached correctly") - } - - if ts.GetDuration().Seconds() != 29*60 || nts.GetDuration().Seconds() != 1*60 { - t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) - } - if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { - t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) - } -} - -func TestLeftMargin(t *testing.T) { - i := &Interval{WeekDays: []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}} - t1 := time.Date(2012, time.February, 5, 23, 45, 0, 0, time.UTC) - t2 := time.Date(2012, time.February, 6, 0, 10, 0, 0, time.UTC) - ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} - oldDuration := ts.GetDuration() - nts := i.Split(ts) - if ts.TimeStart != t1 || ts.TimeEnd != time.Date(2012, time.February, 6, 0, 0, 0, 0, time.UTC) { - t.Error("Incorrect first half", ts) - } - if nts.TimeStart != time.Date(2012, time.February, 6, 0, 0, 0, 0, time.UTC) || nts.TimeEnd != t2 { - t.Error("Incorrect second half", nts) - } - if nts.Interval != i { - t.Error("Interval not attached correctly") - } - if ts.GetDuration().Seconds() != 15*60 || nts.GetDuration().Seconds() != 10*60 { - t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) - } - if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { - t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) - } -} - -func TestLeftHourMargin(t *testing.T) { - i := &Interval{Month: time.December, MonthDay: 1, StartTime: "09:00:00"} - t1 := time.Date(2012, time.December, 1, 8, 45, 0, 0, time.UTC) - t2 := time.Date(2012, time.December, 1, 9, 20, 0, 0, time.UTC) - ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} - oldDuration := ts.GetDuration() - nts := i.Split(ts) - if ts.TimeStart != t1 || ts.TimeEnd != time.Date(2012, time.December, 1, 9, 0, 0, 0, time.UTC) { - t.Error("Incorrect first half", ts) - } - if nts.TimeStart != time.Date(2012, time.December, 1, 9, 0, 0, 0, time.UTC) || nts.TimeEnd != t2 { - t.Error("Incorrect second half", nts) - } - if nts.Interval != i { - t.Error("Interval not attached correctly") - } - if ts.GetDuration().Seconds() != 15*60 || nts.GetDuration().Seconds() != 20*60 { - t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) - } - if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { - t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) - } -} - -func TestEnclosingMargin(t *testing.T) { - i := &Interval{WeekDays: []time.Weekday{time.Sunday}} - t1 := time.Date(2012, time.February, 5, 17, 45, 0, 0, time.UTC) - t2 := time.Date(2012, time.February, 5, 18, 10, 0, 0, time.UTC) - ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} - nts := i.Split(ts) - if ts.TimeStart != t1 || ts.TimeEnd != t2 || nts != nil { - t.Error("Incorrect enclosing", ts) - } - if ts.Interval != i { - t.Error("Interval not attached correctly") - } -} - -func TestOutsideMargin(t *testing.T) { - i := &Interval{WeekDays: []time.Weekday{time.Monday}} - t1 := time.Date(2012, time.February, 5, 17, 45, 0, 0, time.UTC) - t2 := time.Date(2012, time.February, 5, 18, 10, 0, 0, time.UTC) - ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} - result := i.Split(ts) - if result != nil { - t.Error("Interval not split correctly") - } -} - func BenchmarkIntervalFull(b *testing.B) { i := &Interval{Month: time.February, MonthDay: 1, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartTime: "14:30:00", EndTime: "15:00:00"} d := time.Date(2012, time.February, 1, 14, 30, 0, 0, time.UTC) diff --git a/timespans/intervals.go b/timespans/intervals.go index 35f8dd7ec..17d1f258e 100644 --- a/timespans/intervals.go +++ b/timespans/intervals.go @@ -125,48 +125,3 @@ func (i *Interval) getLeftMargin(t time.Time) (rigthtTime time.Time) { } return time.Date(year, month, day, hour, min, sec, nsec, loc) } - -/* -Splits the given timespan according to how it relates to the interval. -It will modify the endtime of the received timespan and it will return -a new timespan starting from the end of the received one. -The interval will attach itself to the timespan that overlaps the interval. -*/ -func (i *Interval) Split(ts *TimeSpan) (nts *TimeSpan) { - // if the span is not in interval return nil - if !i.ContainsSpan(ts) { - return - } - // if the span is enclosed in the interval try to set as new interval and return nil - if i.ContainsFullSpan(ts) { - ts.SetInterval(i) - return - } - // if only the start time is in the interval split he interval - if i.Contains(ts.TimeStart) { - splitTime := i.getRightMargin(ts.TimeStart) - ts.SetInterval(i) - if splitTime == ts.TimeStart { - return - } - oldTimeEnd := ts.TimeEnd - ts.TimeEnd = splitTime - - nts = &TimeSpan{TimeStart: splitTime, TimeEnd: oldTimeEnd} - return - } - // if only the end time is in the interval split the interval - if i.Contains(ts.TimeEnd) { - splitTime := i.getLeftMargin(ts.TimeEnd) - if splitTime == ts.TimeEnd { - return - } - oldTimeEnd := ts.TimeEnd - ts.TimeEnd = splitTime - - nts = &TimeSpan{TimeStart: splitTime, TimeEnd: oldTimeEnd} - nts.SetInterval(i) - return - } - return -} diff --git a/timespans/timespans.go b/timespans/timespans.go index 188657772..d4ef90f80 100644 --- a/timespans/timespans.go +++ b/timespans/timespans.go @@ -2,6 +2,7 @@ package timespans import ( "time" + //"log" ) /* @@ -9,6 +10,7 @@ A unit in which a call will be split that has a specific price related interval */ type TimeSpan struct { TimeStart, TimeEnd time.Time + ActivationPeriod *ActivationPeriod Interval *Interval } @@ -34,6 +36,13 @@ func (ts *TimeSpan) GetCost() (cost float64) { return } +/* +Returns true if the given time is inside timespan range. +*/ +func (ts *TimeSpan) Contains(t time.Time) bool { + return t.After(ts.TimeStart) && t.Before(ts.TimeEnd) +} + /* will set ne interval as spans's interval if new ponder is greater then span's interval ponder or if the ponders are equal and new price is lower then spans's interval price @@ -47,4 +56,59 @@ func (ts *TimeSpan) SetInterval(i *Interval) { } } +/* +Splits the given timespan according to how it relates to the interval. +It will modify the endtime of the received timespan and it will return +a new timespan starting from the end of the received one. +The interval will attach itself to the timespan that overlaps the interval. +*/ +func (ts *TimeSpan) SplitByInterval(i *Interval) (nts *TimeSpan) { + // if the span is not in interval return nil + if !i.ContainsSpan(ts) { + return + } + // if the span is enclosed in the interval try to set as new interval and return nil + if i.ContainsFullSpan(ts) { + ts.SetInterval(i) + return + } + // if only the start time is in the interval split the interval + if i.Contains(ts.TimeStart) { + splitTime := i.getRightMargin(ts.TimeStart) + ts.SetInterval(i) + if splitTime == ts.TimeStart { + return + } + oldTimeEnd := ts.TimeEnd + ts.TimeEnd = splitTime + nts = &TimeSpan{TimeStart: splitTime, TimeEnd: oldTimeEnd} + return + } + // if only the end time is in the interval split the interval + if i.Contains(ts.TimeEnd) { + splitTime := i.getLeftMargin(ts.TimeEnd) + if splitTime == ts.TimeEnd { + return + } + oldTimeEnd := ts.TimeEnd + ts.TimeEnd = splitTime + + nts = &TimeSpan{TimeStart: splitTime, TimeEnd: oldTimeEnd} + nts.SetInterval(i) + return + } + return +} + +/* +Splits the given timespan on activation period's activation time. +*/ +func (ts *TimeSpan) SplitByActivationPeriod(ap *ActivationPeriod) *TimeSpan { + if !ts.Contains(ap.ActivationTime) { + return nil + } + oldTimeEnd := ts.TimeEnd + ts.TimeEnd = ap.ActivationTime + return &TimeSpan{TimeStart: ap.ActivationTime, TimeEnd: oldTimeEnd, ActivationPeriod: ap} +} diff --git a/timespans/timespans_test.go b/timespans/timespans_test.go index 108831e44..92e9887da 100644 --- a/timespans/timespans_test.go +++ b/timespans/timespans_test.go @@ -1,10 +1,171 @@ package timespans import ( - "time" "testing" + "time" ) +func TestRightMargin(t *testing.T) { + i := &Interval{WeekDays: []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}} + t1 := time.Date(2012, time.February, 3, 23, 45, 0, 0, time.UTC) + t2 := time.Date(2012, time.February, 4, 0, 10, 0, 0, time.UTC) + ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} + oldDuration := ts.GetDuration() + nts := ts.SplitByInterval(i) + if ts.TimeStart != t1 || ts.TimeEnd != time.Date(2012, time.February, 3, 23, 59, 59, 0, time.UTC) { + t.Error("Incorrect first half", ts) + } + if nts.TimeStart != time.Date(2012, time.February, 3, 23, 59, 59, 0, time.UTC) || nts.TimeEnd != t2 { + t.Error("Incorrect second half", nts) + } + if ts.Interval != i { + t.Error("Interval not attached correctly") + } + + if ts.GetDuration().Seconds() != 15*60-1 || nts.GetDuration().Seconds() != 10*60+1 { + t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), ts.GetDuration().Seconds()) + } + + if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { + t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) + } +} + +func TestRightHourMargin(t *testing.T) { + i := &Interval{WeekDays: []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}, EndTime: "17:59:00"} + t1 := time.Date(2012, time.February, 3, 17, 30, 0, 0, time.UTC) + t2 := time.Date(2012, time.February, 3, 18, 00, 0, 0, time.UTC) + ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} + oldDuration := ts.GetDuration() + nts := ts.SplitByInterval(i) + if ts.TimeStart != t1 || ts.TimeEnd != time.Date(2012, time.February, 3, 17, 59, 00, 0, time.UTC) { + t.Error("Incorrect first half", ts) + } + if nts.TimeStart != time.Date(2012, time.February, 3, 17, 59, 00, 0, time.UTC) || nts.TimeEnd != t2 { + t.Error("Incorrect second half", nts) + } + if ts.Interval != i { + t.Error("Interval not attached correctly") + } + + if ts.GetDuration().Seconds() != 29*60 || nts.GetDuration().Seconds() != 1*60 { + t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) + } + if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { + t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) + } +} + +func TestLeftMargin(t *testing.T) { + i := &Interval{WeekDays: []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday}} + t1 := time.Date(2012, time.February, 5, 23, 45, 0, 0, time.UTC) + t2 := time.Date(2012, time.February, 6, 0, 10, 0, 0, time.UTC) + ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} + oldDuration := ts.GetDuration() + nts := ts.SplitByInterval(i) + if ts.TimeStart != t1 || ts.TimeEnd != time.Date(2012, time.February, 6, 0, 0, 0, 0, time.UTC) { + t.Error("Incorrect first half", ts) + } + if nts.TimeStart != time.Date(2012, time.February, 6, 0, 0, 0, 0, time.UTC) || nts.TimeEnd != t2 { + t.Error("Incorrect second half", nts) + } + if nts.Interval != i { + t.Error("Interval not attached correctly") + } + if ts.GetDuration().Seconds() != 15*60 || nts.GetDuration().Seconds() != 10*60 { + t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) + } + if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { + t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) + } +} + +func TestLeftHourMargin(t *testing.T) { + i := &Interval{Month: time.December, MonthDay: 1, StartTime: "09:00:00"} + t1 := time.Date(2012, time.December, 1, 8, 45, 0, 0, time.UTC) + t2 := time.Date(2012, time.December, 1, 9, 20, 0, 0, time.UTC) + ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} + oldDuration := ts.GetDuration() + nts := ts.SplitByInterval(i) + if ts.TimeStart != t1 || ts.TimeEnd != time.Date(2012, time.December, 1, 9, 0, 0, 0, time.UTC) { + t.Error("Incorrect first half", ts) + } + if nts.TimeStart != time.Date(2012, time.December, 1, 9, 0, 0, 0, time.UTC) || nts.TimeEnd != t2 { + t.Error("Incorrect second half", nts) + } + if nts.Interval != i { + t.Error("Interval not attached correctly") + } + if ts.GetDuration().Seconds() != 15*60 || nts.GetDuration().Seconds() != 20*60 { + t.Error("Wrong durations.for Intervals", ts.GetDuration().Seconds(), nts.GetDuration().Seconds()) + } + if ts.GetDuration().Seconds()+nts.GetDuration().Seconds() != oldDuration.Seconds() { + t.Errorf("The duration has changed: %v + %v != %v", ts.GetDuration().Seconds(), nts.GetDuration().Seconds(), oldDuration.Seconds()) + } +} + +func TestEnclosingMargin(t *testing.T) { + i := &Interval{WeekDays: []time.Weekday{time.Sunday}} + t1 := time.Date(2012, time.February, 5, 17, 45, 0, 0, time.UTC) + t2 := time.Date(2012, time.February, 5, 18, 10, 0, 0, time.UTC) + ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} + nts := ts.SplitByInterval(i) + if ts.TimeStart != t1 || ts.TimeEnd != t2 || nts != nil { + t.Error("Incorrect enclosing", ts) + } + if ts.Interval != i { + t.Error("Interval not attached correctly") + } +} + +func TestOutsideMargin(t *testing.T) { + i := &Interval{WeekDays: []time.Weekday{time.Monday}} + t1 := time.Date(2012, time.February, 5, 17, 45, 0, 0, time.UTC) + t2 := time.Date(2012, time.February, 5, 18, 10, 0, 0, time.UTC) + ts := &TimeSpan{TimeStart: t1, TimeEnd: t2} + result := ts.SplitByInterval(i) + if result != nil { + t.Error("Interval not split correctly") + } +} + +func TestContains(t *testing.T) { + t1 := time.Date(2012, time.February, 5, 17, 45, 0, 0, time.UTC) + t2 := time.Date(2012, time.February, 5, 17, 55, 0, 0, time.UTC) + t3 := time.Date(2012, time.February, 5, 17, 50, 0, 0, time.UTC) + ts := TimeSpan{TimeStart: t1, TimeEnd: t2} + if ts.Contains(t1) { + t.Error("It should NOT contain ", t1) + } + if ts.Contains(t2) { + t.Error("It should NOT contain ", t1) + } + if !ts.Contains(t3) { + t.Error("It should contain ", t3) + } +} + +func TestSplitByActivationTime(t *testing.T) { + t1 := time.Date(2012, time.February, 5, 17, 45, 0, 0, time.UTC) + t2 := time.Date(2012, time.February, 5, 17, 55, 0, 0, time.UTC) + t3 := time.Date(2012, time.February, 5, 17, 50, 0, 0, time.UTC) + ts := TimeSpan{TimeStart: t1, TimeEnd: t2} + ap1 := &ActivationPeriod{ActivationTime: t1} + ap2 := &ActivationPeriod{ActivationTime: t2} + ap3 := &ActivationPeriod{ActivationTime: t3} + + if ts.SplitByActivationPeriod(ap1) != nil { + t.Error("Error spliting on left margin") + } + if ts.SplitByActivationPeriod(ap2) != nil { + t.Error("Error spliting on right margin") + } + result := ts.SplitByActivationPeriod(ap3) + if result.TimeStart != t3 || result.TimeEnd != t2 { + t.Error("Error spliting on interior") + } +} + func TestTimespanGetCost(t *testing.T) { t1 := time.Date(2012, time.February, 5, 17, 45, 0, 0, time.UTC) t2 := time.Date(2012, time.February, 5, 17, 55, 0, 0, time.UTC) @@ -36,4 +197,3 @@ func TestSetInterval(t *testing.T) { t.Error("Bigger ponder interval should win") } } -