package scheduling import ( apperrors "brainbuffer/pkg/brainbuffer/infrastructure/errors" "github.com/pkg/errors" "github.com/robfig/cron/v3" "time" ) type Pattern string func (pattern Pattern) NextTime(fromTime time.Time) (*time.Time, error) { schedule, err := pattern.Parse() if err != nil { return nil, err } nextTime := schedule.Next(fromTime) return &nextTime, nil } func (pattern Pattern) NextTimesUntil(fromTime time.Time, untilTime time.Time) ([]time.Time, error) { schedule, err := pattern.Parse() if err != nil { return nil, err } nextTimes := make([]time.Time, 0, 0) for nextTime := schedule.Next(fromTime); nextTime.Before(untilTime); nextTime = schedule.Next(nextTime) { nextTimes = append(nextTimes, nextTime) } return nextTimes, nil } func (pattern Pattern) NextNTimes(fromTime time.Time, n int) ([]time.Time, error) { schedule, err := pattern.Parse() if err != nil { return nil, err } nextTimes := make([]time.Time, n) for nextTime, i := schedule.Next(fromTime), 0; i < n; i++ { nextTimes = append(nextTimes, nextTime) nextTime = schedule.Next(nextTime) } return nextTimes, nil } func (pattern Pattern) MatchesTime(t time.Time, precision time.Duration) (*time.Time, error) { if precision > 24*time.Hour { return nil, errors.New("unsupported precision value") } matchingTime, err := pattern.NextTime(time.Now()) if err != nil { return nil, err } truncMatchingTime := matchingTime.Truncate(precision) truncT := t.Truncate(precision) for !truncMatchingTime.Equal(truncT) && truncMatchingTime.Before(truncT) { matchingTime, _ = pattern.NextTime(*matchingTime) truncMatchingTime = matchingTime.Truncate(precision) } if truncMatchingTime.Equal(truncT) { return matchingTime, nil } else { return nil, nil } } func (pattern Pattern) Parse() (cron.Schedule, error) { schedule, err := cron.ParseStandard(string(pattern)) if err != nil { return nil, apperrors.UnknownError{Err: err} } return schedule, nil } type Patterns []Pattern func (patterns Patterns) NextTime(fromTime time.Time) (*time.Time, Pattern, error) { nextTimes := make(map[Pattern]time.Time) for i, val := range patterns { nextTime, err := patterns[i].NextTime(fromTime) if err != nil { return nil, "", err } nextTimes[val] = *nextTime } earliestNextTime := nextTimes[patterns[0]] earliestNextTimePattern := patterns[0] for k, v := range nextTimes { if v.Before(earliestNextTime) { earliestNextTime = v earliestNextTimePattern = k } } return &earliestNextTime, earliestNextTimePattern, nil }