A powerful Go cron expression parser and task scheduler that supports standard cron syntax, second-level precision, timezone control, and custom clock mechanisms.
Forked from robfig/cron
- Standard Cron Syntax - Default support for standard 5-field cron expressions (minute, hour, day, month, weekday); optional second field support
- Predefined Schedules - Support for convenient expressions like @hourly, @daily, @weekly, @monthly, @yearly
- Fixed Intervals - Fixed time interval scheduling using @every syntax
- Timezone Support - Global and per-task timezone configuration
- Dynamic Management - Add, remove, and view tasks at runtime
- Thread-Safe - All operations are carefully designed to ensure concurrency safety
- Multiple Clocks - Support for default system clock, simulated clock, and custom clocks
Free control of time through the Clock interface, supporting:
- DefaultClock - Uses system clock (default)
- FakeClock - Simulated clock for unit testing
- Custom Implementation - Such as passing in NTP precise network time
go get github.com/banbox/cron/v3Requires Go 1.11 or higher (using Go Modules).
package main
import (
"fmt"
"github.com/banbox/cron/v3"
)
func main() {
c := cron.New()
// Execute at the 30th minute of every hour
c.AddFunc("30 * * * *", func() {
fmt.Println("Executes once per hour")
})
// Start the scheduler
c.Start()
// Block main program
select {}
}// Support for second-level precision
c := cron.New(cron.WithSeconds())
// Execute every second
c.AddFunc("* * * * * *", func() {
fmt.Println("Executes every second")
})
// @hourly, @daily, @weekly, @monthly, @yearly
c.AddFunc("@hourly", func() { fmt.Println("Every hour") })
// Execute every 1 hour 30 minutes
c.AddFunc("@every 1h30m", func() {
fmt.Println("Executes every 90 minutes")
})
c.Start()import "time"
// Global timezone setting
loc, _ := time.LoadLocation("Asia/Shanghai")
c := cron.New(cron.WithClock(cron.NewDefaultClock(loc)))
// Specify timezone for individual task
c.AddFunc("CRON_TZ=Asia/Tokyo 0 6 * * *", func() {
fmt.Println("Executes at 6 AM Tokyo time every day")
})
c.Start()c := cron.New()
// Add task and get ID
id, _ := c.AddFunc("@every 1m", func() {
fmt.Println("Task executing")
})
c.Start()
// View all tasks
for _, entry := range c.Entries() {
fmt.Printf("Task %d: Next execution time %v\n", entry.ID, entry.Next)
}
// Remove task
c.Remove(id)
// Stop scheduler
ctx := c.Stop()
<-ctx.Done() // Wait for all running tasks to completetype MyJob struct {
Name string
}
func (j MyJob) Run() {
fmt.Printf("Executing task: %s\n", j.Name)
}
c := cron.New()
c.AddJob("@every 1m", MyJob{Name: "Data Sync"})
c.Start()func TestMultipleExecutions(t *testing.T) {
startTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
fakeClock := cron.NewFakeClock(time.UTC, startTime)
c := cron.New(cron.WithClock(fakeClock), cron.WithSeconds())
count := 0
c.AddFunc("0 0 * * * *", func() { count++ })
c.Start()
defer c.Stop()
// Advance 24 hours, should execute 24 times
c.RunTo(startTime.Add(24 * time.Hour))
if count != 24 {
t.Errorf("Expected 24 executions, got %d", count)
}
}cron has built-in bntp support, allowing you to use NTP as a time source (standard network time) to ensure tasks are triggered accurately at the correct network time.
package main
import (
"fmt"
"time"
"github.com/banbox/cron/v3"
"github.com/banbox/bntp"
)
func main() {
// Create cron scheduler using ntp time source
loc, _ := time.LoadLocation("Asia/Shanghai")
ntpClock := NewNtpClock(loc, bntp.LangGlobal)
c := cron.New(cron.WithClock(ntpClock))
// Add task
c.AddFunc("* * * * *", func() {
realTime := bntp.UTCStamp()
sysTime := time.Now().UnixMilli()
fmt.Println("system: %d, real: %d", sysTime, realTime)
})
c.Start()
// Block main program
select {}
}You can also use other custom time sources, but you need to implement the Clock interface. You can refer to NtpClock as an example.
Then use the cron.WithClock() option to pass in your custom time source.
30 * * * * At the 30th minute of every hour
0 0 * * * Every day at midnight
0 0 1 * * First day of every month at midnight
0 0 * * 0 Every Sunday at midnight
*/15 * * * * Every 15 minutes
0 9-17 * * * Every hour from 9 AM to 5 PM
MIT License