Parse cron specification strings into Schedule objects that determine when jobs should run.
// ParseStandard returns a Schedule representing the given standard cron spec.
// It requires 5 entries: minute, hour, day of month, month, and day of week.
// Also accepts descriptors like "@midnight" and "@every 1h30m".
func ParseStandard(standardSpec string) (Schedule, error)Parameters:
standardSpec string - Standard cron spec or descriptorReturns:
Schedule - Parsed schedule objecterror - Error if spec is invalidUsage:
import "github.com/robfig/cron/v3"
// Standard 5-field cron expression
sched, err := cron.ParseStandard("30 * * * *")
if err != nil {
log.Fatal(err)
}
// Descriptor
sched, _ := cron.ParseStandard("@hourly")
// Interval
sched, _ := cron.ParseStandard("@every 5m")
// Use with Schedule method
c := cron.New()
job := MyJob{}
c.Schedule(sched, job)Create a parser with custom field configurations.
// NewParser creates a Parser with custom options.
// Panics if more than one Optional field is configured.
func NewParser(options ParseOption) ParserType Definitions:
type Parser struct {
// contains unexported fields
}
type ParseOption int
const (
Second ParseOption = 1 << iota // Seconds field, default 0
SecondOptional // Optional seconds field, default 0
Minute // Minutes field, default 0
Hour // Hours field, default 0
Dom // Day of month field, default *
Month // Month field, default *
Dow // Day of week field, default *
DowOptional // Optional day of week field, default *
Descriptor // Allow descriptors (@monthly, etc.)
)Usage:
// Parser with required seconds field (6 total fields)
parser := cron.NewParser(
cron.Second | cron.Minute | cron.Hour |
cron.Dom | cron.Month | cron.Dow | cron.Descriptor,
)
// Parse a 6-field spec
sched, err := parser.Parse("30 0 * * * *") // Every hour at 30 seconds
if err != nil {
log.Fatal(err)
}
// Parser without time fields (3 fields: day, month, day-of-week)
dateParser := cron.NewParser(cron.Dom | cron.Month | cron.Dow)
sched, _ := dateParser.Parse("15 3 *") // 15th day, March, any weekday// Parse returns a Schedule representing the given spec.
// Accepts crontab specs and features configured by NewParser.
func (p Parser) Parse(spec string) (Schedule, error)Usage:
// Create parser with seconds
parser := cron.NewParser(
cron.Second | cron.Minute | cron.Hour |
cron.Dom | cron.Month | cron.Dow | cron.Descriptor,
)
// Parse various specs
specs := []string{
"0 30 * * * *", // Every hour at 30 minutes, 0 seconds
"*/5 * * * * *", // Every 5 seconds
"@every 10s", // Every 10 seconds
}
for _, spec := range specs {
sched, err := parser.Parse(spec)
if err != nil {
log.Printf("Failed to parse %s: %v", spec, err)
continue
}
fmt.Printf("Next run: %v\n", sched.Next(time.Now()))
}All parsed 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
}
type ScheduleParser interface {
Parse(spec string) (Schedule, error)
}Field name | Mandatory? | Allowed values | Allowed special characters
---------- | ---------- | -------------- | --------------------------
Minutes | Yes | 0-59 | * / , -
Hours | Yes | 0-23 | * / , -
Day of month | Yes | 1-31 | * / , - ?
Month | Yes | 1-12 or JAN-DEC | * / , -
Day of week | Yes | 0-6 or SUN-SAT | * / , - ?Examples:
// Every hour on the half hour
"30 * * * *"
// Every day at 3:30 AM
"30 3 * * *"
// Every Monday at midnight
"0 0 * * 1"
// At 4:30 PM on the 15th of each month
"30 16 15 * *"
// Multiple times: 3-6am and 8-11pm
"30 3-6,20-23 * * *"
// Every 15 minutes
"*/15 * * * *"
// First day of every month
"0 0 1 * *"Asterisk ( * )
* * * * * = every minuteSlash ( / )
*/15 * * * * = every 15 minutes10-30/5 * * * * = every 5 minutes from 10 to 30Comma ( , )
0 9,12,15 * * * = 9am, 12pm, 3pm* * * * MON,WED,FRI = Monday, Wednesday, FridayHyphen ( - )
0 9-17 * * * = every hour from 9am to 5pm* * 1-15 * * = first 15 days of monthQuestion mark ( ? )
* (for day-of-month or day-of-week)0 0 ? * MON = every Monday at midnightPredefined schedule aliases:
Descriptor | Description | Equivalent To
----- | ----------- | -------------
@yearly or @annually | Once a year, midnight, Jan. 1st | 0 0 1 1 *
@monthly | Once a month, midnight, first of month | 0 0 1 * *
@weekly | Once a week, midnight between Sat/Sun | 0 0 * * 0
@daily or @midnight | Once a day, midnight | 0 0 * * *
@hourly | Once an hour, beginning of hour | 0 * * * *Examples:
c := cron.New()
c.AddFunc("@yearly", func() { fmt.Println("Happy New Year!") })
c.AddFunc("@monthly", func() { fmt.Println("Start of month") })
c.AddFunc("@weekly", func() { fmt.Println("Weekly report") })
c.AddFunc("@daily", func() { fmt.Println("Daily backup") })
c.AddFunc("@hourly", func() { fmt.Println("Hourly check") })Fixed duration intervals starting from when added or cron starts.
Format: @every <duration>
Examples:
c := cron.New()
// Every 5 minutes
c.AddFunc("@every 5m", func() { fmt.Println("5 min") })
// Every 1 hour 30 minutes 10 seconds
c.AddFunc("@every 1h30m10s", func() { fmt.Println("1.5 hours") })
// Every 30 seconds
c.AddFunc("@every 30s", func() { fmt.Println("30 sec") })
// Every 24 hours
c.AddFunc("@every 24h", func() { fmt.Println("Daily") })Note: The interval does not account for job runtime. If a job takes 3 minutes and runs every 5 minutes, there will be only 2 minutes between executions.
By default, all schedules use the machine's local timezone (or the timezone set with WithLocation).
// All specs use time.Local
c := cron.New()
c.AddFunc("0 6 * * *", func() { fmt.Println("6am local time") })
// All specs use America/New_York
nyc, _ := time.LoadLocation("America/New_York")
c := cron.New(cron.WithLocation(nyc))
c.AddFunc("0 6 * * *", func() { fmt.Println("6am New York time") })Override timezone for individual schedules using CRON_TZ= or TZ= prefix:
c := cron.New() // Uses time.Local
// This job runs at 6am Tokyo time
c.AddFunc("CRON_TZ=Asia/Tokyo 0 6 * * ?", func() {
fmt.Println("6am Tokyo time")
})
// This job runs at 6am New York time
c.AddFunc("CRON_TZ=America/New_York 0 6 * * ?", func() {
fmt.Println("6am New York time")
})
// This job runs at 6am local time
c.AddFunc("0 6 * * ?", func() {
fmt.Println("6am local time")
})Daylight Saving Time Warning: Jobs scheduled during DST leap-ahead transitions will not run!
Month and day-of-week values are case insensitive:
Months: JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC Weekdays: SUN, MON, TUE, WED, THU, FRI, SAT
// These are all equivalent
"0 0 1 JAN *"
"0 0 1 jan *"
"0 0 1 1 *"
// These are all equivalent
"0 0 * * MON"
"0 0 * * mon"
"0 0 * * 1"// Quartz-compatible format with 6 fields
parser := cron.NewParser(
cron.Second | cron.Minute | cron.Hour |
cron.Dom | cron.Month | cron.Dow | cron.Descriptor,
)
// Must provide seconds field
sched, _ := parser.Parse("0 30 * * * *") // Every hour at 30 minutes, 0 seconds
sched, _ := parser.Parse("*/5 * * * * *") // Every 5 seconds// 5 or 6 fields, seconds defaults to 0 if omitted
parser := cron.NewParser(
cron.SecondOptional | cron.Minute | cron.Hour |
cron.Dom | cron.Month | cron.Dow | cron.Descriptor,
)
// With seconds (6 fields)
sched, _ := parser.Parse("30 0 * * * *")
// Without seconds (5 fields, defaults to 0)
sched, _ := parser.Parse("0 * * * *") // Same as "0 0 * * * *"// Only day, month, weekday
parser := cron.NewParser(cron.Dom | cron.Month | cron.Dow)
sched, _ := parser.Parse("15 * *") // 15th of every month// No @hourly, @daily, etc.
parser := cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow)
// This works
sched, _ := parser.Parse("0 * * * *")
// This fails (descriptors not enabled)
sched, err := parser.Parse("@hourly") // Returns errorpackage main
import (
"fmt"
"log"
"time"
"github.com/robfig/cron/v3"
)
func main() {
// Standard parser
standardSpecs := []string{
"30 * * * *", // Every hour at 30 minutes
"0 0 * * *", // Daily at midnight
"@hourly", // Every hour
"@every 30m", // Every 30 minutes
}
for _, spec := range standardSpecs {
sched, err := cron.ParseStandard(spec)
if err != nil {
log.Printf("Failed to parse %s: %v", spec, err)
continue
}
next := sched.Next(time.Now())
fmt.Printf("Spec: %-20s Next: %v\n", spec, next)
}
// Custom parser with seconds
parser := cron.NewParser(
cron.Second | cron.Minute | cron.Hour |
cron.Dom | cron.Month | cron.Dow | cron.Descriptor,
)
secondSpecs := []string{
"0 30 * * * *", // Every hour at 30 minutes, 0 seconds
"*/10 * * * * *", // Every 10 seconds
"@every 5s", // Every 5 seconds
}
for _, spec := range secondSpecs {
sched, err := parser.Parse(spec)
if err != nil {
log.Printf("Failed to parse %s: %v", spec, err)
continue
}
next := sched.Next(time.Now())
fmt.Printf("Spec: %-20s Next: %v\n", spec, next)
}
// Test timezone handling
spec := "CRON_TZ=Asia/Tokyo 0 6 * * ?"
sched, _ := cron.ParseStandard(spec)
next := sched.Next(time.Now())
fmt.Printf("Spec: %s\nNext: %v\n", spec, next)
}