| package timeutil |
|
|
| import ( |
| "reflect" |
| "slices" |
| "time" |
| ) |
|
|
| type SimpleTimeline = Timeline[time.Time] |
|
|
| func NewSimpleTimeline(times []time.Time) SimpleTimeline { |
| wrapped := make([]Timed[time.Time], len(times)) |
| for i, t := range times { |
| wrapped[i] = AsTimed(func(t time.Time) time.Time { return t })(t) |
| } |
|
|
| return NewTimeline(wrapped) |
| } |
|
|
| |
| func AsTimed[T any](fn func(T) time.Time) func(T) Timed[T] { |
| return func(t T) Timed[T] { |
| return Timed[T]{ |
| val: t, |
| fn: fn, |
| } |
| } |
| } |
|
|
| type Timed[T any] struct { |
| val T |
| fn func(T) time.Time |
| } |
|
|
| func (t Timed[T]) GetTime() time.Time { |
| return t.fn(t.val) |
| } |
|
|
| func (t Timed[T]) GetValue() T { |
| return t.val |
| } |
|
|
| func (t Timed[T]) Equal(other Timed[T]) bool { |
| if !t.GetTime().Equal(other.GetTime()) { |
| return false |
| } |
|
|
| return reflect.DeepEqual(t.GetValue(), other.GetValue()) |
| } |
|
|
| type Timeline[T any] struct { |
| times []Timed[T] |
| } |
|
|
| func NewTimeline[T any](times []Timed[T]) Timeline[T] { |
| |
| times = slices.Clone(times) |
|
|
| slices.SortStableFunc(times, func(a, b Timed[T]) int { |
| return a.GetTime().Compare(b.GetTime()) |
| }) |
|
|
| return Timeline[T]{times: times} |
| } |
|
|
| func (t Timeline[T]) After(at time.Time) Timeline[T] { |
| times := make([]Timed[T], 0, len(t.times)) |
| for _, t := range t.times { |
| if t.GetTime().After(at) { |
| times = append(times, t) |
| } |
| } |
| return NewTimeline(times) |
| } |
|
|
| func (t Timeline[T]) Before(at time.Time) Timeline[T] { |
| times := make([]Timed[T], 0, len(t.times)) |
| for _, t := range t.times { |
| if t.GetTime().Before(at) { |
| times = append(times, t) |
| } |
| } |
| return NewTimeline(times) |
| } |
|
|
| func (t Timeline[T]) GetTimes() []time.Time { |
| times := make([]time.Time, len(t.times)) |
| for i, t := range t.times { |
| times[i] = t.GetTime() |
| } |
| return times |
| } |
|
|
| func (t Timeline[T]) GetAt(idx int) Timed[T] { |
| return t.times[idx] |
| } |
|
|
| func (t Timeline[T]) GetBoundingPeriod() ClosedPeriod { |
| if len(t.times) == 0 { |
| return ClosedPeriod{ |
| From: time.Time{}, |
| To: time.Time{}, |
| } |
| } |
|
|
| return ClosedPeriod{ |
| From: t.times[0].GetTime(), |
| To: t.times[len(t.times)-1].GetTime(), |
| } |
| } |
|
|
| |
| func (t Timeline[T]) GetClosedPeriods() []ClosedPeriod { |
| if len(t.times) == 0 { |
| return []ClosedPeriod{} |
| } |
|
|
| if len(t.times) == 1 { |
| return []ClosedPeriod{ |
| { |
| From: t.times[0].GetTime(), |
| To: t.times[0].GetTime(), |
| }, |
| } |
| } |
|
|
| periods := make([]ClosedPeriod, 0, len(t.times)-1) |
| for i := 0; i < len(t.times)-1; i++ { |
| periods = append(periods, ClosedPeriod{From: t.times[i].GetTime(), To: t.times[i+1].GetTime()}) |
| } |
| return periods |
| } |
|
|
| |
| |
| func (t Timeline[T]) GetOpenPeriods() []OpenPeriod { |
| if len(t.times) == 0 { |
| return []OpenPeriod{} |
| } |
|
|
| periods := make([]OpenPeriod, 0, len(t.times)+1) |
|
|
| |
| firstTime := t.times[0].GetTime() |
| periods = append(periods, OpenPeriod{ |
| From: nil, |
| To: &firstTime, |
| }) |
|
|
| |
| for i := 0; i < len(t.times)-1; i++ { |
| from := t.times[i].GetTime() |
| to := t.times[i+1].GetTime() |
| periods = append(periods, OpenPeriod{ |
| From: &from, |
| To: &to, |
| }) |
| } |
|
|
| |
| lastTime := t.times[len(t.times)-1].GetTime() |
| periods = append(periods, OpenPeriod{ |
| From: &lastTime, |
| To: nil, |
| }) |
|
|
| return periods |
| } |
|
|