spliting in activation periods and in intervals

This commit is contained in:
Radu Ioan Fericean
2012-02-07 16:05:04 +02:00
parent 60f5b9e897
commit 99099a8fb6
8 changed files with 307 additions and 237 deletions

View File

@@ -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)
}
}
}

View File

@@ -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;")

View File

@@ -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,

View File

@@ -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)
}
}

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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}
}

View File

@@ -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")
}
}