Cron and daylight saving time: how to avoid skipped and duplicate jobs
Cron and daylight saving time: skipped and doubled jobs in cronie, systemd, Kubernetes, EventBridge and GitHub Actions, and fixes before Oct 25 and Nov 1.
Cron evaluates schedules against local wall-clock time, so a daylight saving change can make a job run twice, run late or never run. Classic Linux cron daemons try to smooth this over for fixed-time jobs, but the documentation is not fully consistent, and Kubernetes, systemd, AWS and GitHub Actions each handle the problem differently. The safest fix is the same everywhere: keep schedules in UTC or keep local-time jobs out of the hours when clocks move.
When the clocks change in 2026 and 2027
As of October 2026, the next transitions that affect most production schedules are:
- European Union and UK: clocks go back on Sunday, October 25, 2026, at 01:00 UTC, and forward again on Sunday, March 28, 2027, at 01:00 UTC. The EU rule (last Sunday of October and March, 01:00 GMT) comes from Directive 2000/84/EC. In Berlin the hour from 02:00 to 02:59 happens twice on October 25; in London it is 01:00 to 01:59.
- United States: clocks go back at 02:00 local time on Sunday, November 1, 2026, so 01:00 to 01:59 repeats. They jump forward at 02:00 local time on Sunday, March 14, 2027, so 02:00 to 02:59 does not exist that day. NIST documents the US rule: second Sunday in March, first Sunday in November.
Because US zones change one at a time, a scheduler set to America/Los_Angeles shifts three hours after one set to America/New_York. You can list the exact transitions for any zone on your own machine with zdump -v -c 2026,2028 America/New_York.
The two failure modes
- Autumn (fall back): one local hour happens twice. A job scheduled at 01:30 in New York matches both the first and the second 01:30 on November 1, unless the scheduler deduplicates it.
- Spring (spring forward): one local hour never happens. A job scheduled at 02:30 has no matching minute that day, so it is either skipped or moved, depending on the scheduler.
Jobs that run every few minutes are mostly unaffected by either case: they simply keep firing on the new clock. The risk sits with daily, weekly and monthly jobs pinned to a time between roughly 01:00 and 03:00 local time, which is exactly where backups, report generation and cleanup tasks tend to be placed.
How Linux cron handles daylight saving time
cronie (RHEL, Fedora, Amazon Linux and others)
The cron(8) page for cronie says local time changes of less than three hours get special treatment, but only for jobs set at a specific time or with a granularity coarser than one hour. If the clock moves forward, jobs that fell in the skipped interval run immediately after the change. If it moves back, the daemon avoids running the same job twice. Changes of more than three hours are treated as clock or time zone corrections and take effect at once.
The crontab(5) page from the same project describes the plain matching rule instead: non-existent times never match, so those jobs do not run, and times that occur twice cause matching jobs to run twice. Cronie also supports a per-table CRON_TZ variable, and the manual does not say how the special handling interacts with it. Given the two descriptions, treat any fixed-time job in the transition window as unpredictable until you have tested it on your own build.
Vixie cron (Debian and Ubuntu)
Debian's cron(8) manual describes the same three-hour logic: after a forward jump, skipped jobs run soon after the change; after a backward jump, jobs in the repeated period are not re-run. It also spells out the exception: jobs using @hourly or a wildcard in the hour or minute field follow the new time immediately, so an hourly job is not deduplicated or caught up and may run one time more or one time fewer than usual on the transition day.
systemd timers
An OnCalendar= expression can carry its own zone. According to systemd.time(7), the zone can be the literal UTC, the local zone or an IANA name, for example *-*-* 02:30:00 UTC or Mon *-*-* 00:00:00 Pacific/Auckland. The manual does not describe what happens to non-existent or repeated local times, so check the actual next elapse times with systemd-analyze calendar before the transition rather than assuming.
Two settings in systemd.timer(5) are worth knowing:
- Persistent=true stores the last trigger time on disk and starts the service immediately if a run was missed, for example while the machine was powered off. It only applies to calendar timers.
- OnClockChange= and OnTimezoneChange= trigger a unit when the realtime clock jumps or the system zone changes. They are triggers in their own right, not a DST-correction mode.
Pure interval jobs can use monotonic settings such as OnUnitActiveSec=, which the manual describes as independent of wall-clock time and time zones.
Kubernetes CronJob time zones
The CronJob documentation marks the .spec.timeZone field as stable since Kubernetes v1.27. Without it, the kube-controller-manager interprets the schedule in its own local time zone, which on most managed control planes you do not control. Setting timeZone: "Etc/UTC" makes the schedule explicit.
Putting CRON_TZ= or TZ= inside .spec.schedule is not supported, and the API server rejects it with a validation error. The documentation does not describe daylight saving behaviour for an IANA zone such as Europe/Berlin, so test a 02:30 schedule in a non-production cluster before relying on it. Two related controls matter on transition nights:
- startingDeadlineSeconds sets how late a job may start; past the deadline the run is skipped and counted as failed.
- concurrencyPolicy: Forbid prevents a second run from starting while the first is still active, which limits damage if a duplicate is ever created.
The controller also refuses to catch up if it has missed more than 100 schedules, a separate issue usually caused by clock skew or a long controller outage. For version support, see our note on the Kubernetes 1.34 end of life.
AWS EventBridge Scheduler and scheduled rules
EventBridge Scheduler accepts an IANA time zone for cron and one-time schedules and documents its daylight saving behaviour clearly:
- In spring, a cron schedule that falls on a non-existent time is skipped for that day and resumes the next day.
- In autumn, the schedule runs once, before the shift, and is not repeated.
- For rate(1 days), a day means 24 hours, so a rate schedule drifts by an hour against local time after each change.
- Schedules in UTC, or in zones without daylight saving, are not adjusted.
The older EventBridge scheduled rules, which AWS now labels legacy, have no time zone setting; AWS's examples are all expressed in UTC+0. A rule meant to run at 09:00 New York time therefore moves by an hour against local time twice a year unless you edit it.
GitHub Actions schedules
As of October 2026, the GitHub Actions schedule event runs in UTC by default and accepts an optional timezone key with an IANA name next to the cron line. GitHub says a time that falls in the skipped spring hour moves to the next valid time, so 02:30 becomes 03:00. The page does not describe the repeated autumn hour. GitHub also warns that scheduled runs can be delayed under load, with the start of every hour named as a busy period, and that some queued jobs may be dropped, so avoid minute 0 for anything important.
Practical checklist before October 25 and November 1
- Run servers and schedulers in UTC. Convert to local time only where a business rule demands it, such as a report due at 08:00 in an office.
- Keep local-time jobs out of 01:00 to 03:00. That window covers the transition hour in the US, the UK and central Europe.
- Make jobs idempotent. A run keyed by date, a lock file or a database row that records completion turns an accidental second run into a no-op.
- Declare the zone explicitly. Use .spec.timeZone in Kubernetes, a zone suffix in OnCalendar=, the time zone parameter in EventBridge Scheduler and the timezone key in GitHub Actions instead of inheriting a host default.
- Test with a fake clock. Tools such as libfaketime let you start a process with a shifted clock, and systemd-analyze calendar prints upcoming trigger times for a timer expression.
- Watch the morning after. Check job histories for missing or doubled runs on October 25 (Europe) and November 1 (North America).
More scheduler and pipeline coverage sits in our DevOps tooling and cloud infrastructure sections.
Frequently asked questions
Does cron run a job twice when the clocks go back?
It depends on the implementation. The cronie and Debian cron daemons document logic that avoids re-running fixed-time jobs in the repeated hour, while cronie's crontab(5) page describes jobs running twice, so test your own build or move the job outside the window.
Does cron skip jobs when the clocks go forward?
For fixed-time jobs, cronie and Debian cron say jobs from the skipped hour run immediately or soon after the change. EventBridge Scheduler skips that day's run, and GitHub Actions moves it to the next valid time.
What time zone does a Kubernetes CronJob use?
Without .spec.timeZone, the schedule follows the kube-controller-manager's local time zone. Since v1.27 the timeZone field is stable and accepts IANA names such as Etc/UTC or America/New_York.
Should servers run on UTC to avoid daylight saving problems?
Yes, UTC has no daylight saving transitions, so schedules evaluated in UTC never hit a skipped or repeated hour. You still need a local zone for jobs that must follow business hours, and those should avoid the 01:00 to 03:00 window.