Timezones and DST
How a schedule's timezone and daylight saving time decide when it fires.
A schedule's timezone is an IANA zone name, entered in the Timezone (IANA)
field on the Cadence step. The field starts with your browser's zone, or
UTC if the browser does not report one. The server looks the name up with
Python's zoneinfo and refuses a name it cannot find; the server's response
carries unknown IANA timezone '…'. Legacy names in the zone database, such as CET
and EST, are accepted. Write the name as the database spells it:
europe/madrid was refused in a test run where Europe/Madrid was accepted.
How a fire time is computed¶
The expression is evaluated on the local clock of the schedule's zone:
0 9 * * * means 09:00 local time, whatever the zone's offset from UTC is that
day. The server computes each next fire as a local time with croniter and
zoneinfo, converts it to UTC, and stores the UTC instant. Pentr applies no
offset arithmetic of its own. The ticker compares that stored instant with the
current time.
At a daylight-saving change¶
The results below come from running the application's cron code for
Europe/Madrid, where clocks go back from 03:00 to 02:00 on 25 October 2026 and
forward from 02:00 to 03:00 on 28 March 2027.
A time outside the changed hour keeps its local time. 0 9 * * * fires at
09:00 Madrid time on both sides of the change. Its UTC time moves by an hour.
| Date | Local time | UTC |
|---|---|---|
| 27 March 2027 | 09:00 CET | 08:00 |
| 28 March 2027 | 09:00 CEST | 07:00 |
| 29 March 2027 | 09:00 CEST | 07:00 |
A local time that does not exist fires at the end of the gap. On 28 March
2027 the Madrid clock has no 02:30. 30 2 * * * fires that day at 03:00 local
time, then returns to 02:30 the next day.
| Date | Local time | UTC |
|---|---|---|
| 27 March 2027 | 02:30 CET | 01:30 |
| 28 March 2027 | 03:00 CEST | 01:00 |
| 29 March 2027 | 02:30 CEST | 00:30 |
A local time that occurs twice fires twice. On 25 October 2026 the Madrid
clock shows 02:30 twice, an hour apart. 30 2 * * * fires at both.
| Date | Local time | UTC |
|---|---|---|
| 24 October 2026 | 02:30 CEST | 00:30 |
| 25 October 2026 | 02:30 CEST | 00:30 |
| 25 October 2026 | 02:30 CET | 01:30 |
| 26 October 2026 | 02:30 CET | 01:30 |
The ticker computes each next run time from the moment of the tick that fired
the previous one, and a step-by-step run of that computation from 24 October
produced the same two fires on the 25th. They are two occurrences. Each creates
its own engagement, and the second is subject to the
plan cap like any other: if the first is still
queued or running an hour later and the organization is at its cap, the
second is skipped.
The presets all fire at 09:00, which in Europe/Madrid is outside both
changes. In another zone, a custom time inside that zone's change behaves as in
the tables above: runs for Australia/Lord_Howe, whose clocks move by 30
minutes, and America/Havana, which changes at midnight, gave the same results.
DST and the one-hour floor¶
The one-hour floor compares fire times on the local clock. Across a change that is not the same as elapsed time, and the check errs in both directions:
30 1,2 * * *inEurope/Madridis accepted. On 28 March 2027 it fires at 01:30 CET and 03:00 CEST — 00:30 and 01:00 UTC, 30 minutes apart. On the local clock the gap is an hour and a half.30 2 * * 0, Sundays at 02:30, inEurope/Madridis refused withobserved a 0:00:00 gap. 25 October 2026 is a Sunday inside the check's sample, and its two 02:30 fires are an hour apart in elapsed time and zero apart on the local clock.
30 2 * * *, the daily form of the same time, is accepted: its sample ends in
July 2026 and does not reach October. It still fires twice on 25 October, as the
table above shows.
How the console shows times¶
The console shows every schedule time in the schedule's own zone — not in UTC and not in your browser's zone. The Next 3 runs preview labels each time with the zone name. On the Schedules list, the next and last times are in the zone printed on the same row. The date and time format follows your browser's locale, and no UTC offset is shown, so the two 02:30 fires on a fall-back night display the same. If the browser does not recognise the zone name, the time is shown in the browser's own zone instead.
The HTTP API returns schedule times as UTC ISO 8601 strings; the conversion to the schedule's zone happens in the browser.
Next: Caps and skips.
Last updated 2026-09-22