82 lines
1.8 KiB
Go
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
|
|
}
|