76 lines
2.0 KiB
Go
76 lines
2.0 KiB
Go
package forecast
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
"unicode"
|
|
|
|
"gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil"
|
|
"gitea.maximumdirect.net/eric/weatherreporter/internal/weatherdata"
|
|
)
|
|
|
|
type DaypartDefinition struct {
|
|
Name string `json:"name"`
|
|
Start string `json:"start"`
|
|
End string `json:"end"`
|
|
}
|
|
|
|
// CanonicalDaypartKey returns the stable identity for a configured daypart name.
|
|
func CanonicalDaypartKey(value string) string {
|
|
lower := strings.ToLower(strings.TrimSpace(value))
|
|
var out strings.Builder
|
|
lastUnderscore := false
|
|
for _, r := range lower {
|
|
if unicode.IsLetter(r) || unicode.IsDigit(r) {
|
|
out.WriteRune(r)
|
|
lastUnderscore = false
|
|
continue
|
|
}
|
|
if !lastUnderscore {
|
|
out.WriteByte('_')
|
|
lastUnderscore = true
|
|
}
|
|
}
|
|
return strings.Trim(out.String(), "_")
|
|
}
|
|
|
|
type DaypartWindow struct {
|
|
Name string `json:"name"`
|
|
Start time.Time `json:"start"`
|
|
End time.Time `json:"end"`
|
|
Period timeutil.Period `json:"period"`
|
|
}
|
|
|
|
func ResolveDayparts(date time.Time, location *time.Location, definitions []DaypartDefinition) ([]DaypartWindow, error) {
|
|
if len(definitions) == 0 {
|
|
return nil, fmt.Errorf("daypart definitions are required")
|
|
}
|
|
windows := make([]DaypartWindow, 0, len(definitions))
|
|
for i, def := range definitions {
|
|
if def.Name == "" {
|
|
return nil, fmt.Errorf("daypart[%d].name is required", i)
|
|
}
|
|
startClock, err := timeutil.ParseClock(def.Start)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("daypart[%d].start: %w", i, err)
|
|
}
|
|
endClock, err := timeutil.ParseClock(def.End)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("daypart[%d].end: %w", i, err)
|
|
}
|
|
period := timeutil.ClockWindow(date, location, startClock, endClock)
|
|
windows = append(windows, DaypartWindow{
|
|
Name: def.Name,
|
|
Start: period.Start,
|
|
End: period.End,
|
|
Period: period,
|
|
})
|
|
}
|
|
return windows, nil
|
|
}
|
|
|
|
func PeriodForForecastPeriod(period weatherdata.ForecastPeriod) timeutil.Period {
|
|
return timeutil.Period{Start: period.StartTime, End: period.EndTime}
|
|
}
|