mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
spliting in activation periods and in intervals
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;")
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user