evcc-io/core/planner/helper.go
2024-08-03 15:23:50 +02:00

82 lines
1.8 KiB
Go

package planner
import (
"time"
"github.com/evcc-io/evcc/api"
)
// Start returns the earliest slot's start time
func Start(plan api.Rates) time.Time {
var start time.Time
for _, slot := range plan {
if start.IsZero() || slot.Start.Before(start) {
start = slot.Start
}
}
return start
}
func End(plan api.Rates) time.Time {
var end time.Time
for _, slot := range plan {
if end.IsZero() || slot.End.After(end) {
end = slot.End
}
}
return end
}
// Duration returns the sum of all slot's durations
func Duration(plan api.Rates) time.Duration {
var duration time.Duration
for _, slot := range plan {
slotDuration := slot.End.Sub(slot.Start)
duration += slotDuration
}
return duration
}
// AverageCost returns the time-weighted average cost
func AverageCost(plan api.Rates) float64 {
var cost float64
var duration time.Duration
for _, slot := range plan {
slotDuration := slot.End.Sub(slot.Start)
duration += slotDuration
cost += float64(slotDuration) * slot.Price
}
return cost / float64(duration)
}
// SlotAt returns the slot for the given time or an empty slot
func SlotAt(time time.Time, plan api.Rates) api.Rate {
for _, slot := range plan {
if !slot.Start.After(time) && slot.End.After(time) {
return slot
}
}
return api.Rate{}
}
// SlotHasSuccessor returns if the slot has an immediate successor.
// Does not require the plan to be sorted by start time.
func SlotHasSuccessor(r api.Rate, plan api.Rates) bool {
for _, slot := range plan {
if r.End.Equal(slot.Start) {
return true
}
}
return false
}
// IsFirst returns if the slot is the first slot in the plan.
// Does not require the plan to be sorted by start time.
func IsFirst(r api.Rate, plan api.Rates) bool {
for _, slot := range plan {
if r.Start.After(slot.Start) {
return false
}
}
return true
}