2023-01-12 18:24:11 -05:00
package actionssummerwindnet
2021-05-03 22:03:49 +09:00
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
}