Skip to content

netresearch/go-cron

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Go Reference CI CodeQL OpenSSF Scorecard Go Report Card License: MIT

go-cron

A maintained fork of robfig/cron — the most popular cron library for Go — with critical bug fixes, DST handling improvements, and modern toolchain support.

Why?

The original robfig/cron has been unmaintained since 2020, accumulating 50+ open PRs and several critical panic bugs that affect production systems. Rather than waiting indefinitely, this fork provides:

Issue Original This Fork
TZ= parsing panics Crashes on malformed input Fixed (#554, #555)
Chain decorators Entry.Run() bypasses chains Properly invokes wrappers (#551)
DST spring-forward Jobs silently skipped Runs immediately (ISC behavior, #541)
Go version Stuck on 1.13 Go 1.25+ with modern toolchain

Installation

go get github.com/netresearch/go-cron
import cron "github.com/netresearch/go-cron"

Note

Requires Go 1.25 or later.

Migrating from robfig/cron

Drop-in replacement — just change the import path:

// Before
import "github.com/robfig/cron/v3"

// After
import cron "github.com/netresearch/go-cron"

The API is 100% compatible with robfig/cron v3.

Tip

See docs/MIGRATION.md for a comprehensive migration guide including behavioral differences, type changes, and troubleshooting.

Quick Start

package main

import (
    "fmt"
    "time"

    cron "github.com/netresearch/go-cron"
)

func main() {
    c := cron.New()

    // Run every minute
    c.AddFunc("* * * * *", func() {
        fmt.Println("Every minute:", time.Now())
    })

    // Run at specific times
    c.AddFunc("30 3-6,20-23 * * *", func() {
        fmt.Println("In the range 3-6am, 8-11pm")
    })

    // With timezone
    c.AddFunc("CRON_TZ=Asia/Tokyo 30 04 * * *", func() {
        fmt.Println("4:30 AM Tokyo time")
    })

    c.Start()

    // Keep running...
    select {}
}

Cron Expression Format

Standard 5-field cron format (minute-first):

Field Required Values 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 * / , - ?

Predefined Schedules

Entry Description Equivalent
@yearly Once a year, midnight, Jan 1 0 0 1 1 *
@monthly Once a month, midnight, first day 0 0 1 * *
@weekly Once a week, midnight Sunday 0 0 * * 0
@daily Once a day, midnight 0 0 * * *
@hourly Once an hour, beginning of hour 0 * * * *
@every <duration> Every interval e.g., @every 1h30m

Seconds Field (Optional)

Enable Quartz-compatible seconds field:

// Seconds field required
cron.New(cron.WithSeconds())

// Seconds field optional
cron.New(cron.WithParser(cron.NewParser(
    cron.SecondOptional | cron.Minute | cron.Hour |
    cron.Dom | cron.Month | cron.Dow | cron.Descriptor,
)))

Timezone Support

Specify timezone per-schedule using CRON_TZ= prefix:

// Runs at 6am New York time
c.AddFunc("CRON_TZ=America/New_York 0 6 * * *", myFunc)

// Legacy TZ= prefix also supported
c.AddFunc("TZ=Europe/Berlin 0 9 * * *", myFunc)

Or set default timezone for all jobs:

nyc, _ := time.LoadLocation("America/New_York")
c := cron.New(cron.WithLocation(nyc))

Daylight Saving Time (DST) Handling

This library implements ISC cron-compatible DST behavior:

Transition Behavior
Spring Forward (hour skipped) Jobs in skipped hour run immediately after transition
Fall Back (hour repeats) Jobs run once, during first occurrence
Midnight DST (midnight doesn't exist) Automatically normalized to valid time

Tip

For DST-sensitive applications, schedule jobs outside typical transition hours (1-3 AM) or use UTC.

See docs/DST_HANDLING.md for comprehensive DST documentation including examples, testing strategies, and edge cases.

Job Wrappers (Middleware)

Add cross-cutting behavior using chains:

// Apply to all jobs
c := cron.New(cron.WithChain(
    cron.Recover(logger),              // Recover panics
    cron.SkipIfStillRunning(logger),   // Skip if previous still running
))

// Apply to specific job
job := cron.NewChain(
    cron.DelayIfStillRunning(logger),  // Queue if previous still running
).Then(myJob)

Available wrappers:

  • Recover — Catch panics, log, and continue
  • SkipIfStillRunning — Skip execution if previous run hasn't finished
  • DelayIfStillRunning — Queue execution until previous run finishes

Logging

Compatible with go-logr/logr:

// Verbose logging
c := cron.New(cron.WithLogger(
    cron.VerbosePrintfLogger(log.New(os.Stdout, "cron: ", log.LstdFlags)),
))

API Reference

Full documentation: pkg.go.dev/github.com/netresearch/go-cron

Contributing

Contributions are welcome! Please read CONTRIBUTING.md before submitting PRs.

Security

For security issues, please see SECURITY.md.

License

MIT License — see LICENSE for details.


This fork is maintained by Netresearch. The original cron library was created by Rob Figueiredo.

About

Maintained fork of robfig/cron - Go cron job scheduler with panic fixes, DST handling, and modern toolchain

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Languages

  • Go 98.1%
  • Makefile 1.6%
  • Shell 0.3%