openmeter / pkg /timeutil /timeline.go
Leon4gr45's picture
Upload folder using huggingface_hub (part 10)
6380833 verified
Raw
History Blame Contribute Delete
3.65 kB
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)
}
// AsTimed returns a function that converts a value of type T to a Timed value.
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] {
// sort copy of times ASC
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(),
}
}
// GetClosedPeriods returns the closed periods between the times in the timeline.
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
}
// GetOpenPeriods returns the open periods between the times in the timeline.
// For non-empty timelines, the first and last periods will be open at the start and end of the timeline respectively while the rest will effectively be closed.
func (t Timeline[T]) GetOpenPeriods() []OpenPeriod {
if len(t.times) == 0 {
return []OpenPeriod{}
}
periods := make([]OpenPeriod, 0, len(t.times)+1)
// First period: open at start, closed at first time
firstTime := t.times[0].GetTime()
periods = append(periods, OpenPeriod{
From: nil,
To: &firstTime,
})
// Middle periods: closed at both ends
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,
})
}
// Last period: closed at last time, open at end
lastTime := t.times[len(t.times)-1].GetTime()
periods = append(periods, OpenPeriod{
From: &lastTime,
To: nil,
})
return periods
}