Support for custom time source (e.g. NTP) in cron scheduler
Summary
Currently, cron/v3 relies solely on the system clock (time.Now()) for its scheduling logic. I'd like to request a feature that allows users to configure a custom time source, such as one provided by github.com/beevik/ntp, for cases where accurate timekeeping is critical and the system clock may not be reliable or synced in time.
On some embedded boards, the system time is initially incorrect because the application starts running before the NTP service has completed time synchronization. As a result, any time-based logic (e.g., scheduling with cron/v3) that relies on time.Now() may execute at unexpected times.
To address this, we often fetch the current time from an external NTP source (e.g., using github.com/beevik/ntp) and apply a delta to correct for the offset. However, since cron/v3 does not support injecting a custom time provider, we cannot align its scheduling with the corrected time reference.
Supporting a pluggable time source would greatly improve reliability in these environments.
Motivation
In some environments (e.g., embedded devices, VMs without NTP sync, or network-isolated systems), the system clock might drift or be incorrect. For these cases, relying on an external time source like NTP can ensure that scheduled tasks run at the expected wall-clock time.
For example, instead of using time.Now(), developers might want to plug in a function that returns a time from a trusted source like:
ntp.Time("pool.ntp.org")
Proposed Solution
Expose a functional option like:
cron.New(cron.WithTimeFunc(func() time.Time {
return ntpTimeCache.Load().(time.Time)
}))
This would allow users to override the default time.Now() behavior used internally by the scheduler, similar to how logrus or other libraries allow customizable time providers.
Benefits
Supports more accurate scheduling when system time is unreliable
Useful in distributed systems or offline environments
Offers flexibility for advanced use cases without affecting default behavior
Compatibility
This would be an opt-in feature and fully backward compatible. If no custom time function is set, cron continues using time.Now() as usual.
Thanks
Thanks for the great work on cron — it's been very helpful! Let me know if you're open to a PR or if you'd prefer to discuss design first.
I am very interested in this requirement and I will submit the relevant code in about a week. To Pull MR
Already Support, Please Maintainer check #552
fork支持了。提取了 Clock 接口,支持多种时钟:
DefaultClock - 使用系统时钟(默认) FakeClock - 模拟时钟用于单元测试 NtpClock - 使用NTP网络精确时钟 自定义实现 - 如基于系统时钟自行设置时间偏移
Solution available in maintained fork
This feature has been implemented in netresearch/go-cron, a maintained fork of this library.
Implementation: Added WithClock(Clock) option for custom time source injection, plus a complete FakeClock implementation for deterministic testing:
// Create a fake clock for testing
fakeClock := cron.NewFakeClock(time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC))
c := cron.New(cron.WithClock(fakeClock))
c.Start()
// Advance time deterministically
fakeClock.Advance(time.Hour) // Triggers scheduled jobs without waiting
How to migrate:
// Change import from:
import "github.com/robfig/cron/v3"
// To:
import cron "github.com/netresearch/go-cron"
The API is 100% backward compatible. See the migration guide for details.
Related: netresearch/go-cron#4, netresearch/go-cron#34