Built-in Schedule implementations for different scheduling patterns.
All schedules implement the Schedule interface.
type Schedule interface {
// Next returns the next activation time, later than the given time.
// Next is invoked initially, and then each time the job is run.
Next(time.Time) time.Time
}Traditional crontab-based schedule with bit field representation.
// SpecSchedule specifies a duty cycle based on a traditional crontab
// specification. It is computed initially and stored as bit sets.
type SpecSchedule struct {
Second uint64 // Seconds bit field (0-59)
Minute uint64 // Minutes bit field (0-59)
Hour uint64 // Hours bit field (0-23)
Dom uint64 // Day of month bit field (1-31)
Month uint64 // Month bit field (1-12)
Dow uint64 // Day of week bit field (0-6)
Location *time.Location // Override location for this schedule
}
// Next returns the next time this schedule is activated, greater than the
// given time. If no time can be found within five years, returns the zero time.
func (s *SpecSchedule) Next(t time.Time) time.TimeUsage:
import "github.com/robfig/cron/v3"
// Typically created via parsing
sched, _ := cron.ParseStandard("30 * * * *")
// Can also construct manually (advanced)
specSched := &cron.SpecSchedule{
Second: 1 << 0, // 0 seconds
Minute: 1 << 30, // 30 minutes
Hour: ^uint64(0), // All hours (*)
Dom: ^uint64(0), // All days of month (*)
Month: ^uint64(0), // All months (*)
Dow: ^uint64(0), // All days of week (*)
Location: time.UTC,
}
// Get next activation time
next := specSched.Next(time.Now())
fmt.Println("Next run:", next)The Location field determines how the schedule interprets times:
// Parse with timezone
sched, _ := cron.ParseStandard("CRON_TZ=America/New_York 0 6 * * ?")
// The SpecSchedule will have Location set to America/New_York
// Or set manually
tokyo, _ := time.LoadLocation("Asia/Tokyo")
specSched.Location = tokyoSimple recurring schedule with a fixed delay between activations.
// ConstantDelaySchedule represents a simple recurring duty cycle.
// Does not support jobs more frequent than once a second.
type ConstantDelaySchedule struct {
Delay time.Duration
}
// Next returns the next activation time.
// Rounds to the second.
func (schedule ConstantDelaySchedule) Next(t time.Time) time.Time// Every returns a schedule that activates once every duration.
// Delays of less than a second are rounded up to 1 second.
// Subsecond fields are truncated.
func Every(duration time.Duration) ConstantDelayScheduleUsage:
import (
"time"
"github.com/robfig/cron/v3"
)
// Every 5 minutes
sched := cron.Every(5 * time.Minute)
// Every 1 hour
sched := cron.Every(time.Hour)
// Every 30 seconds
sched := cron.Every(30 * time.Second)
// Less than 1 second rounds up to 1 second
sched := cron.Every(500 * time.Millisecond) // Becomes 1 second
// Use with scheduler
c := cron.New()
c.Schedule(cron.Every(10*time.Minute), myJob)Example:
sched := cron.Every(5 * time.Minute)
now := time.Now()
next1 := sched.Next(now)
next2 := sched.Next(next1)
next3 := sched.Next(next2)
fmt.Println("Now: ", now)
fmt.Println("Next 1:", next1) // now + 5 minutes
fmt.Println("Next 2:", next2) // next1 + 5 minutes
fmt.Println("Next 3:", next3) // next2 + 5 minutesThe interval does NOT account for job runtime:
c := cron.New()
// Job takes 3 minutes to run, scheduled every 5 minutes
c.AddFunc("@every 5m", func() {
fmt.Println("Starting...")
time.Sleep(3 * time.Minute)
fmt.Println("Done")
})
// Timeline:
// 0:00 - Job starts
// 0:03 - Job finishes
// 0:05 - Job starts again (only 2 minutes of idle time)
// 0:08 - Job finishes
// 0:10 - Job starts againUse job wrappers like DelayIfStillRunning or SkipIfStillRunning to handle overlapping executions.
You can implement custom Schedule types for specialized scheduling logic.
type Schedule interface {
Next(time.Time) time.Time
}Example - Business Days Only:
// BusinessDaySchedule runs at a specific time on business days only
type BusinessDaySchedule struct {
Hour int
Minute int
Loc *time.Location
}
func (s BusinessDaySchedule) Next(t time.Time) time.Time {
// Convert to schedule timezone
if s.Loc != nil {
t = t.In(s.Loc)
}
// Start with next occurrence
next := time.Date(t.Year(), t.Month(), t.Day(), s.Hour, s.Minute, 0, 0, t.Location())
// If already passed today, move to tomorrow
if next.Before(t) || next.Equal(t) {
next = next.Add(24 * time.Hour)
}
// Skip weekends
for next.Weekday() == time.Saturday || next.Weekday() == time.Sunday {
next = next.Add(24 * time.Hour)
}
return next
}
// Usage
c := cron.New()
bizSchedule := BusinessDaySchedule{
Hour: 9,
Minute: 0,
Loc: time.UTC,
}
c.Schedule(bizSchedule, myJob)Example - Specific Dates:
// SpecificDatesSchedule runs at specific predetermined dates/times
type SpecificDatesSchedule struct {
Dates []time.Time
index int
}
func (s *SpecificDatesSchedule) Next(t time.Time) time.Time {
// Find next date after t
for s.index < len(s.Dates) {
if s.Dates[s.index].After(t) {
next := s.Dates[s.index]
s.index++
return next
}
s.index++
}
// No more dates
return time.Time{}
}
// Usage
dates := []time.Time{
time.Date(2024, 1, 15, 10, 0, 0, 0, time.UTC),
time.Date(2024, 2, 15, 10, 0, 0, 0, time.UTC),
time.Date(2024, 3, 15, 10, 0, 0, 0, time.UTC),
}
c := cron.New()
c.Schedule(&SpecificDatesSchedule{Dates: dates}, myJob)Best for:
Characteristics:
Examples:
Best for:
Characteristics:
Examples:
Best for:
Characteristics:
Examples:
package main
import (
"fmt"
"time"
"github.com/robfig/cron/v3"
)
func main() {
c := cron.New()
// SpecSchedule via parsing
c.AddFunc("30 * * * *", func() {
fmt.Println("SpecSchedule: Every hour at 30 minutes")
})
// ConstantDelaySchedule via Every()
c.Schedule(cron.Every(15*time.Minute), cron.FuncJob(func() {
fmt.Println("ConstantDelaySchedule: Every 15 minutes")
}))
// ConstantDelaySchedule via @every descriptor
c.AddFunc("@every 10m", func() {
fmt.Println("ConstantDelaySchedule: Every 10 minutes")
})
// Custom schedule
bizDay := &BusinessDaySchedule{
Hour: 9,
Minute: 0,
Loc: time.UTC,
}
c.Schedule(bizDay, cron.FuncJob(func() {
fmt.Println("Custom: Business days at 9 AM")
}))
c.Start()
defer c.Stop()
// Show next run times
for _, entry := range c.Entries() {
fmt.Printf("Entry %d: Next run at %v\n", entry.ID, entry.Next)
}
select {}
}