evcc-io/tariff/fixed/month.go
2025-10-31 15:25:53 +00:00

133 lines
2.3 KiB
Go

package fixed
import (
"errors"
"fmt"
"slices"
"strconv"
"strings"
)
//go:generate go tool enumer -type Month
type Month int
const (
January Month = iota
February
March
April
May
June
July
August
September
October
November
December
)
var Year = []Month{January, February, March, April, May, June, July, August, September, October, November, December}
var shortMonths = map[string]Month{
// english
"jan": January,
"feb": February,
"mar": March,
"apr": April,
"may": May,
"jun": June,
"jul": July,
"aug": August,
"sep": September,
"oct": October,
"nov": November,
"dec": December,
// german
// "jan": January,
// "feb": February,
"mär": March,
// "apr": April,
"mai": May,
// "jun": June,
// "jul": July,
// "aug": August,
// "sep": September,
"okt": October,
// "nov": November,
"dez": December,
}
// ParseMonth parses a single month
func ParseMonth(s string) (Month, error) {
s = strings.ToLower(strings.TrimSpace(s))
// full string
if m, err := MonthString(s); err == nil {
return m, nil
}
// short string
if m, ok := shortMonths[s]; ok {
return m, nil
}
m, err := strconv.Atoi(s)
if m < 1 || m > 12 || err != nil {
return 0, fmt.Errorf("invalid month: %s", s)
}
return Month(m - 1), nil
}
// ParseMonths converts a months string into a slice of individual months
// Months format:
//
// month[-month][, ...]
func ParseMonths(s string) ([]Month, error) {
var res []Month
for segment := range strings.SplitSeq(s, ",") {
fromto := strings.SplitN(segment, "-", 2)
if len(fromto) == 0 {
return nil, fmt.Errorf("invalid month range: %s", segment)
}
fromToFrom := fromto[0]
// single empty segment
if len(fromto) == 1 && strings.TrimSpace(fromToFrom) == "" {
return slices.Clone(Year), nil
}
from, err := ParseMonth(fromToFrom)
if err != nil {
return nil, err
}
res = append(res, from)
if len(fromto) == 2 {
to, err := ParseMonth(fromto[1])
if err != nil {
return nil, err
}
if to < from {
to += 12
}
for m := from + 1; m <= to; m++ {
res = append(res, m%12)
}
}
}
if len(res) > 12 {
return nil, errors.New("too many months")
}
if len(slices.Compact(slices.Sorted(slices.Values(res)))) < len(res) {
return nil, errors.New("duplicate months")
}
return res, nil
}