package taskutil import ( "time" "github.com/robfig/cron/v3" ) // cronParser is a shared parser instance. Standard 5-field cron with // optional descriptors (@hourly, @daily, @weekly, @monthly, etc.). var cronParser = cron.NewParser( cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor, ) // NextRunFromSchedule computes the next run time from a cron expression // and timezone. Returns nil for "once" schedules (one-shot tasks). // // Replaces the v0.27.1 hand-rolled parseDailyCron with full 5-field // cron support via robfig/cron/v3. func NextRunFromSchedule(schedule, timezone string) *time.Time { if schedule == "once" { return nil } now := time.Now() if tz, err := time.LoadLocation(timezone); err == nil { now = now.In(tz) } sched, err := cronParser.Parse(schedule) if err != nil { // Unparseable — log at call site, caller decides fallback return nil } next := sched.Next(now).UTC() return &next } // ValidateCron checks whether a cron expression is valid. // Returns nil for valid expressions, error describing the problem otherwise. // "once" is always valid (one-shot schedule). func ValidateCron(schedule string) error { if schedule == "once" { return nil } _, err := cronParser.Parse(schedule) return err }