123 lines
3.0 KiB
Go
123 lines
3.0 KiB
Go
package actionssummerwindnet
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/teambition/rrule-go"
|
|
)
|
|
|
|
type RecurrenceRule struct {
|
|
Frequency string
|
|
UntilTime time.Time
|
|
}
|
|
|
|
type Period struct {
|
|
StartTime time.Time
|
|
EndTime time.Time
|
|
}
|
|
|
|
func (r *Period) String() string {
|
|
if r == nil {
|
|
return ""
|
|
}
|
|
|
|
return r.StartTime.Format(time.RFC3339) + "-" + r.EndTime.Format(time.RFC3339)
|
|
}
|
|
|
|
func MatchSchedule(now time.Time, startTime, endTime time.Time, recurrenceRule RecurrenceRule) (*Period, *Period, error) {
|
|
return calculateActiveAndUpcomingRecurringPeriods(
|
|
now,
|
|
startTime,
|
|
endTime,
|
|
recurrenceRule.Frequency,
|
|
recurrenceRule.UntilTime,
|
|
)
|
|
}
|
|
|
|
func calculateActiveAndUpcomingRecurringPeriods(now, startTime, endTime time.Time, frequency string, untilTime time.Time) (*Period, *Period, error) {
|
|
var freqValue rrule.Frequency
|
|
|
|
var freqDurationDay int
|
|
var freqDurationMonth int
|
|
var freqDurationYear int
|
|
|
|
switch frequency {
|
|
case "Daily":
|
|
freqValue = rrule.DAILY
|
|
freqDurationDay = 1
|
|
case "Weekly":
|
|
freqValue = rrule.WEEKLY
|
|
freqDurationDay = 7
|
|
case "Monthly":
|
|
freqValue = rrule.MONTHLY
|
|
freqDurationMonth = 1
|
|
case "Yearly":
|
|
freqValue = rrule.YEARLY
|
|
freqDurationYear = 1
|
|
case "":
|
|
if now.Before(startTime) {
|
|
return nil, &Period{StartTime: startTime, EndTime: endTime}, nil
|
|
}
|
|
|
|
if now.Before(endTime) {
|
|
return &Period{StartTime: startTime, EndTime: endTime}, nil, nil
|
|
}
|
|
|
|
return nil, nil, nil
|
|
default:
|
|
return nil, nil, fmt.Errorf(`invalid freq %q: It must be one of "Daily", "Weekly", "Monthly", and "Yearly"`, frequency)
|
|
}
|
|
|
|
freqDurationLater := time.Date(
|
|
now.Year()+freqDurationYear,
|
|
time.Month(int(now.Month())+freqDurationMonth),
|
|
now.Day()+freqDurationDay,
|
|
now.Hour(), now.Minute(), now.Second(), now.Nanosecond(), now.Location(),
|
|
)
|
|
|
|
freqDuration := freqDurationLater.Sub(now)
|
|
|
|
overrideDuration := endTime.Sub(startTime)
|
|
if overrideDuration > freqDuration {
|
|
return nil, nil, fmt.Errorf("override's duration %s must be equal to sor shorter than the duration implied by freq %q (%s)", overrideDuration, frequency, freqDuration)
|
|
}
|
|
|
|
rrule, err := rrule.NewRRule(rrule.ROption{
|
|
Freq: freqValue,
|
|
Dtstart: startTime,
|
|
Until: untilTime,
|
|
})
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
overrideDurationBefore := now.Add(-overrideDuration + 1)
|
|
activeOverrideStarts := rrule.Between(overrideDurationBefore, now, true)
|
|
|
|
var active *Period
|
|
|
|
if len(activeOverrideStarts) > 1 {
|
|
return nil, nil, fmt.Errorf("[bug] unexpted number of active overrides found: %v", activeOverrideStarts)
|
|
} else if len(activeOverrideStarts) == 1 {
|
|
active = &Period{
|
|
StartTime: activeOverrideStarts[0],
|
|
EndTime: activeOverrideStarts[0].Add(overrideDuration),
|
|
}
|
|
}
|
|
|
|
oneSecondLater := now.Add(1)
|
|
upcomingOverrideStarts := rrule.Between(oneSecondLater, freqDurationLater, true)
|
|
|
|
var next *Period
|
|
|
|
if len(upcomingOverrideStarts) > 0 {
|
|
next = &Period{
|
|
StartTime: upcomingOverrideStarts[0],
|
|
EndTime: upcomingOverrideStarts[0].Add(overrideDuration),
|
|
}
|
|
}
|
|
|
|
return active, next, nil
|
|
}
|