145 lines
4.2 KiB
Go
145 lines
4.2 KiB
Go
package report
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil"
|
|
)
|
|
|
|
func Resolve(id ID, req ResolveRequest) (Resolved, error) {
|
|
return DefaultRegistry().Resolve(id, req)
|
|
}
|
|
|
|
func (r Registry) Resolve(id ID, req ResolveRequest) (Resolved, error) {
|
|
definition, err := r.Lookup(id)
|
|
if err != nil {
|
|
return Resolved{}, err
|
|
}
|
|
return r.resolveDefinition(definition, req)
|
|
}
|
|
|
|
func (r Registry) BatchReports(batch Batch, req ResolveRequest) ([]Resolved, error) {
|
|
if req.Location == nil {
|
|
req.Location = time.UTC
|
|
}
|
|
if req.Now.IsZero() {
|
|
req.Now = time.Now()
|
|
}
|
|
switch batch {
|
|
case Morning:
|
|
ids := []ID{DailyToday, ThreeDay}
|
|
if req.Now.In(req.Location).Weekday() != time.Sunday {
|
|
ids = append(ids, Weekend)
|
|
}
|
|
return r.resolveIDs(ids, req)
|
|
case Evening:
|
|
return r.resolveIDs([]ID{DailyTomorrow}, req)
|
|
default:
|
|
return nil, fmt.Errorf("unknown batch %q", batch)
|
|
}
|
|
}
|
|
|
|
func (r Registry) resolveIDs(ids []ID, req ResolveRequest) ([]Resolved, error) {
|
|
resolved := make([]Resolved, 0, len(ids))
|
|
for _, id := range ids {
|
|
item, err := r.Resolve(id, req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resolved = append(resolved, item)
|
|
}
|
|
return resolved, nil
|
|
}
|
|
|
|
func (r Registry) resolveDefinition(definition Definition, req ResolveRequest) (Resolved, error) {
|
|
if req.Location == nil {
|
|
req.Location = time.UTC
|
|
}
|
|
if req.Now.IsZero() {
|
|
req.Now = time.Now()
|
|
}
|
|
period, err := definition.ResolvePeriod(req)
|
|
if err != nil {
|
|
return Resolved{}, err
|
|
}
|
|
return Resolved{
|
|
Definition: definition,
|
|
GeneratedAt: req.Now,
|
|
Timezone: req.Location.String(),
|
|
ValidPeriod: period,
|
|
}, nil
|
|
}
|
|
|
|
func resolveDailyToday(req ResolveRequest) (timeutil.Period, error) {
|
|
if !req.Date.IsZero() {
|
|
return timeutil.CivilDay(req.Date, req.Location), nil
|
|
}
|
|
return timeutil.CivilDay(req.Now, req.Location), nil
|
|
}
|
|
|
|
func ParseStormPeriod(start string, end string, location *time.Location) (timeutil.Period, error) {
|
|
if location == nil {
|
|
location = time.UTC
|
|
}
|
|
startTime, err := timeutil.ParseStormTime(start, location)
|
|
if err != nil {
|
|
return timeutil.Period{}, err
|
|
}
|
|
endTime, err := timeutil.ParseStormTime(end, location)
|
|
if err != nil {
|
|
return timeutil.Period{}, err
|
|
}
|
|
period := timeutil.Period{Start: startTime, End: endTime}
|
|
if !period.IsValid() {
|
|
return timeutil.Period{}, fmt.Errorf("storm report requires end time after start time")
|
|
}
|
|
return period, nil
|
|
}
|
|
|
|
func resolveDailyTomorrow(req ResolveRequest) (timeutil.Period, error) {
|
|
return timeutil.CivilDay(req.Now.In(req.Location).AddDate(0, 0, 1), req.Location), nil
|
|
}
|
|
|
|
func resolveThreeDay(req ResolveRequest) (timeutil.Period, error) {
|
|
localNow := req.Now.In(req.Location)
|
|
endDate := localNow.AddDate(0, 0, 3)
|
|
end := time.Date(endDate.Year(), endDate.Month(), endDate.Day(), 0, 0, 0, 0, req.Location)
|
|
return timeutil.Period{Start: localNow, End: end}, nil
|
|
}
|
|
|
|
func resolveWeekend(req ResolveRequest) (timeutil.Period, error) {
|
|
localNow := req.Now.In(req.Location)
|
|
weekday := localNow.Weekday()
|
|
if weekday == time.Sunday {
|
|
return timeutil.Period{}, fmt.Errorf("weekend outlook is not scheduled on Sunday morning")
|
|
}
|
|
|
|
daysUntilSaturday := (int(time.Saturday) - int(weekday) + 7) % 7
|
|
saturday := localNow.AddDate(0, 0, daysUntilSaturday)
|
|
start := time.Date(saturday.Year(), saturday.Month(), saturday.Day(), 0, 0, 0, 0, req.Location)
|
|
if weekday == time.Friday || weekday == time.Saturday {
|
|
friday := start.AddDate(0, 0, -1)
|
|
fridayEvening := time.Date(friday.Year(), friday.Month(), friday.Day(), 18, 0, 0, 0, req.Location)
|
|
start = fridayEvening
|
|
if localNow.After(start) {
|
|
start = localNow
|
|
}
|
|
}
|
|
end := time.Date(saturday.Year(), saturday.Month(), saturday.Day(), 0, 0, 0, 0, req.Location).AddDate(0, 0, 2)
|
|
return timeutil.Period{Start: start, End: end}, nil
|
|
}
|
|
|
|
func resolveStorm(req ResolveRequest) (timeutil.Period, error) {
|
|
if req.StormStart.IsZero() {
|
|
return timeutil.Period{}, fmt.Errorf("storm report requires a start time")
|
|
}
|
|
if req.StormEnd.IsZero() {
|
|
return timeutil.Period{}, fmt.Errorf("storm report requires an end time")
|
|
}
|
|
if !req.StormEnd.After(req.StormStart) {
|
|
return timeutil.Period{}, fmt.Errorf("storm report requires end time after start time")
|
|
}
|
|
return timeutil.Period{Start: req.StormStart, End: req.StormEnd}, nil
|
|
}
|