thread-master/backend/internal/library/publishschedule/slots.go

89 lines
2.0 KiB
Go
Raw Permalink Normal View History

package publishschedule
import (
"sort"
"strings"
"time"
)
type Slot struct {
Weekday int
Time string
}
func BuildSchedule(startAt int64, timezone string, slots []Slot, count int) []int64 {
if count <= 0 {
return nil
}
loc := time.UTC
if strings.TrimSpace(timezone) != "" {
if loaded, err := time.LoadLocation(strings.TrimSpace(timezone)); err == nil {
loc = loaded
}
}
start := time.Now().In(loc)
if startAt > 0 {
start = time.Unix(0, startAt).In(loc)
}
normalized := normalizeSlots(slots)
if len(normalized) == 0 {
out := make([]int64, 0, count)
for i := 0; i < count; i++ {
out = append(out, start.Add(time.Duration(i)*2*time.Hour).UTC().UnixNano())
}
return out
}
out := make([]int64, 0, count)
day := time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, loc)
for len(out) < count {
for _, slot := range normalized {
if int(day.Weekday()) != slot.Weekday {
continue
}
hour, minute, ok := parseHHMM(slot.Time)
if !ok {
continue
}
candidate := time.Date(day.Year(), day.Month(), day.Day(), hour, minute, 0, 0, loc)
if candidate.Before(start) {
continue
}
out = append(out, candidate.UTC().UnixNano())
if len(out) >= count {
break
}
}
day = day.AddDate(0, 0, 1)
}
return out
}
func normalizeSlots(slots []Slot) []Slot {
out := make([]Slot, 0, len(slots))
for _, slot := range slots {
if strings.TrimSpace(slot.Time) == "" {
continue
}
weekday := slot.Weekday
if weekday < 0 || weekday > 6 {
weekday = ((weekday % 7) + 7) % 7
}
out = append(out, Slot{Weekday: weekday, Time: strings.TrimSpace(slot.Time)})
}
sort.Slice(out, func(i, j int) bool {
if out[i].Weekday == out[j].Weekday {
return out[i].Time < out[j].Time
}
return out[i].Weekday < out[j].Weekday
})
return out
}
func parseHHMM(value string) (int, int, bool) {
parsed, err := time.Parse("15:04", strings.TrimSpace(value))
if err != nil {
return 0, 0, false
}
return parsed.Hour(), parsed.Minute(), true
}