Add report registry and valid periods
This commit is contained in:
144
internal/report/period.go
Normal file
144
internal/report/period.go
Normal file
@@ -0,0 +1,144 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user