In short and in plain language
When summer time ends, one hour happens twice. For a shop, this can have effects.
Background tasks that run in this hour may then run twice or not at all. Times in this hour are not clear. Reports for the day can also be wrong.
The article shows how to prepare. You move important tasks to a time without the change.
We check the schedules of your shop in advance. In this night, we pay special attention to tasks that run twice or not at all.
In the night to Sunday, 25 October 2026, Central European Summer Time ends. The hour count is set back by one hour from 3 to 2, and the hour from 2 to 3 occurs twice (German Summer Time Ordinance). For an online shop this is not a footnote. Scheduled tasks that fall into this hour run a second time or not at all, depending on the scheduler. Timestamps in local time become ambiguous for 60 minutes. Daily reports compare a day of 25 hours against a day of 24. The switch happens across Europe at a single moment, 1 a.m. Universal Time (Directive 2000/84/EC), and can therefore be planned to the minute – provided somebody plans it. This article describes the failure patterns that follow from it and the rework that typically prevents them.
Key takeaways
- Central European Summer Time ends on the last Sunday in October at 3 o'clock; the hour count goes back to 2 and the hour from 2 to 3 occurs twice (German Summer Time Ordinance). In 2026 that Sunday is 25 October.
- The legislator gave the doubled hour its own names: 2A for the first and 2B for the second (German Summer Time Ordinance). Anyone storing timestamps in local time does not have exactly this distinction in their data.
- Schedules in local time are affected, but the behaviour depends on the scheduler: in the cronie line, times that occur more than once make matching jobs run twice, and skipped times in spring find no match at all (crontab(5)); the Debian implementation does not re-run jobs in the repeated time and runs skipped ones soon after the change (cron(8), Debian implementation). The cut itself happens EU-wide at 1 a.m. Universal Time (Directive 2000/84/EC).
- The database does not solve this on its own: values in a TIMESTAMP column are converted to UTC from the session time zone when stored and converted back when retrieved, and no time zone identifier is stored with them (MariaDB documentation).
- The conversion rules come from a maintained database whose current release is 2026c, published on 8 July 2026 (IANA Time Zone Database). A system with an outdated rule set computes the wrong result on exactly these days.
What legally happens in the night to 25 October
Legal time in Germany is Central European Time, defined as Coordinated Universal Time plus one hour (German Units and Time Act, section 4). During the period of its introduction, Central European Summer Time takes its place, defined as Universal Time plus two hours (German Units and Time Act, section 4). Exactly one hour of offset lies between the two, and changing that offset is the entire event. The Summer Time Ordinance sets the date: Central European Summer Time ends on the last Sunday in October at 3 o'clock Central European Summer Time (German Summer Time Ordinance, section 2). The last Sunday in October 2026 is 25 October. For the spring counterpart with the opposite sign: summer time begins on the last Sunday in March, in 2026 therefore on 29 March, and the hour count is moved forward from 2 to 3 (German Summer Time Ordinance, section 2).
Notably, the ordinance does not only describe the doubled hour, it names it. The first hour from 2 to 3 carries the designation 2A, the second the designation 2B (German Summer Time Ordinance, section 2). This naming is not a technical curiosity: it is the official acknowledgement that a local time within this hour does not, on its own, denote a point in time. The responsible ministry expressly also determines the designation of the hour appearing twice at the end of Central European Summer Time (German Units and Time Act, section 5). Summer time itself has applied since 2002 for an indefinite period (German Summer Time Ordinance, section 1), and its beginning and end are announced in advance for five consecutive years at a time (German Summer Time Ordinance, section 3). An operational event is hardly ever more predictable.
The change is a point in time, not a period
Why cron jobs run twice or not at all
A classic scheduler compares its fields with the system's current local time. Exactly from this follows the behaviour that the manual page of the cronie line states unusually plainly: non-existent times such as the missing hours during the conversion find no match at all, causing jobs scheduled during those missing times not to be run; times that occur more than once, by contrast, will cause matching jobs to be run twice (crontab(5)). This is not an implementation flaw but the documented consequence of the fact that a local time field is not a unique key during these 60 minutes. A job set to 02:30 local time will be triggered on such a system on 25 October 2026 in hour 2A and again in hour 2B – entirely according to the rules, as far as the scheduler is concerned. It cannot be generalised, though: the cron implementation of the Debian line governs both cases the other way round. When the clock is moved forwards by less than three hours, jobs that would have run in the skipped time are run soon after the change there; when it is moved backwards by less than three hours, jobs that fall into the repeated time are not re-run. Only entries with a fixed time of day are affected, not those with a placeholder in the hour or minute field (cron(8), Debian implementation). Which of the two readings is at work on your own server is answered by its manual page – and that answer decides whether the duplicated, the caught-up or the silent run is the real risk that night.
The second run is rarely harmless. A stock reconciliation that carries deltas forward subtracts the same delta a second time. A dunning run sends the same reminder twice. An invoicing run assigns two number ranges to the same transaction. A payment reconciliation books items twice or fails a uniqueness check and reports an error that nobody can place on Monday. Conversely, the missed run in spring hits hardest those tasks that run only once a day: a nightly backup with a fixed time between 2 and 3 is skipped on a cronie-line scheduler on the March changeover Sunday, and experience shows that the gap is noticed only when somebody attempts a restore. How silent failures of background processes become visible at all is covered in detail by the article on background jobs and cron jobs in a shop; here the separate question of duplicated and skipped runs is at issue. The table below describes a scheduler of the cronie line; on the Debian implementation the duplicated run does not occur and the skipped one is run soon after the change (cron(8), Debian implementation).
| Task | Scheduled local time | End of summer time (October, cronie line) | Start of summer time (March, cronie line) | Rework |
|---|---|---|---|---|
| Stock and price sync | 02:15 | runs twice, deltas are applied twice | does not run, stock lags by one day | schedule in Universal Time, secure the run with a transaction key |
| Dunning and reminder run | 02:30 | sends the same message twice | no dispatch on that day | dispatch lock per transaction and calendar day |
| Invoice and numbering run | 02:45 | two runs compete for the same number range | run is lost, documents shift | lock the transaction, move the run outside 1 to 4 local time |
| Database backup | 02:00 | two backups, doubled storage demand | no backup that night | schedule in Universal Time, verify the result per calendar day |
| Cache and index rebuild | 02:10 | second run displaces the first, briefly cold caches | index stays one day old | uncritical, but move the time window |
| Reporting and metrics run | 03:05 | inconspicuous, but the reporting day has 25 hours | reporting day has 23 hours | keep time series in Universal Time, local time for display only |
The table shows a pattern: what is affected is not the technology but the business logic. Whether a duplicated run causes damage depends on whether the task is repeatable. A cache rebuild tolerates a repetition, a booking does not. The first question before the changeover weekend is therefore not a technical one but a substantive one: which of the tasks running at night change states that cannot be changed twice without consequences? In most shops this list is shorter than it first appears – typically it comes down to a handful of runs around stock, payment and document numbers.
The four failure patterns in live operation
Anyone sorting incident reports after the changeover will as a rule find the same four patterns. They occur independently of each other and have different causes, but they are readily lumped together because they become visible on the same weekend.
The duplicated run
A scheduled task inside the doubled hour is triggered twice on a cronie-line scheduler because its local time occurs twice (crontab(5)). It becomes visible through duplicated documents, duplicated messages or through uniqueness errors in the database.
The missed run
In spring the scheduled local time does not exist: in the cronie line the condition finds no match and the job is skipped (crontab(5)); the Debian implementation runs such jobs soon after the change (cron(8), Debian implementation). Without a success record per calendar day a gap arising this way goes unnoticed until the result is needed.
The ambiguous timestamp
A time from the doubled hour that was stored in local time can no longer be assigned to a point in time afterwards; the ordinance separates these hours as 2A and 2B (German Summer Time Ordinance), storage in local time does not.
The distorted metric
In local time, 25 October 2026 has 25 hours; 29 March had 23. Daily revenue, hourly curves and week-on-week comparisons shift measurably as a result, without anything having changed in the business.
The third pattern is the most expensive because it cannot be repaired. A duplicated run can be reversed, a missed one can be caught up. A timestamp stored in local time without an offset, by contrast, has lost the information about the intended point in time – and lost it for good. For order and payment times, withdrawal periods and audit records this is a problem with a legal dimension, not merely an operational one. Anyone already measuring the transaction path should check the time reference there first; what such a measurement path looks like is described in the article on checkout and transaction monitoring. For Shopware installations, checking the system time zone belongs in the same round as update and extension care, see Shopware maintenance.
Timestamps: what the database stores and what it does not
The most widespread misconception is that the database will take care of it. That is half true. For a TIMESTAMP column the rule is: inserted values are converted from the session's time zone to Coordinated Universal Time when stored, and converted back to the session's time zone when retrieved (MariaDB documentation). Internally, therefore, an unambiguous point in time is held. At the same time, however, no time zone identifier is stored with the value (MariaDB documentation). Uniqueness thus depends entirely on the time zone of the writing session – and that can differ between web process, console run and background service without anyone noticing. A DATETIME column, in turn, stores exactly what was written into it, without any reference; within the doubled hour its content is therefore not resolvable.
The changeover is also the reason why a time zone without a date carries no meaning. In another widely used database this is documented explicitly: when a time zone name containing a daylight saving rule is used, specifying the date is required in order to determine whether standard or daylight-savings time applies (PostgreSQL documentation). The standard for date and time on the internet draws the consequence and defines a timestamp as an unambiguous representation of some instant in time (IETF, RFC 3339); numeric offsets there are calculated as local time minus UTC (IETF, RFC 3339), whereas attempts to label local offsets with alphabetic strings have resulted in poor interoperability in the past (IETF, RFC 3339). Translated into practice: store Universal Time or a value with a numeric offset, display local time.
-- Which time zone does the writing session actually use?
SELECT @@global.time_zone AS global_tz, @@session.time_zone AS session_tz;
-- Orders in the doubled hour of 25 Oct 2026 (local time)
-- Careful: values stored in local time cannot be resolved here
SELECT id, created_at
FROM orders
WHERE created_at >= '2026-10-25 00:00:00'
AND created_at < '2026-10-25 02:00:00';
-- Clean: compute in Universal Time, convert only for display
SELECT id,
created_at AS ts_utc,
CONVERT_TZ(created_at, '+00:00', 'Europe/Berlin') AS ts_local
FROM orders
WHERE created_at >= '2026-10-24 22:00:00'
AND created_at < '2026-10-25 02:00:00';
Calling the conversion with a named region instead of a fixed offset presupposes that the database's time zone tables are populated – otherwise the conversion returns no value and the report stays empty without any error being reported. That is one of the typical silent sources of error on this weekend: the query runs through, the output is empty, and the empty output is read as a result. Anyone reviewing data storage regularly anyway will find the matching steps in the article on database maintenance and optimisation.
A timestamp without a reference is not a time
Reporting: the day with 25 hours
Metrics are formed in local time almost everywhere, because that is the operator's point of view. On 25 October 2026 this day has 25 hours in local time; on 29 March it had 23. Anyone placing daily revenue side by side without correction sees growth in October and a slump in March for which there is no commercial cause. In hourly curves the effect is even clearer: the bucket "02:00 to 03:00" contains the sum of two real hours in October and none at all in March. For night-time revenue this is often a small number; for server-side metrics – requests, queue lengths, error rates – it is a large one. An alert threshold built on hourly averages will as a rule fire without cause during the doubled hour.
The order of magnitude at stake can be placed in a market context: German online retail most recently grew by 3.9 percent to 92.3 billion euros (HDE Online Monitor 2026). A single shop carries a small share of that, but the arithmetic is the same at any size: an hour of the night is a measurable block of revenue, and two night-time hours booked as one distort every comparison built on that day. More important than the absolute figure is the consequence for the report: the changeover day belongs marked, not explained away.
- Keep time series internally in Universal Time and convert to local time only for display
- Mark the two changeover days in the reporting system as exception days so deviations remain explainable
- Base year-on-year comparisons on the same weekday rather than the same date, because the changeover moves across dates
- Widen alert thresholds for the night hours on the changeover weekend or suspend them for 60 minutes
- Label hourly curves so that the doubled hour is recognisable as such
- Deliver exports to accounting with a numeric offset or in Universal Time, not as bare local time
The changeover plan for the week around 25 October
The rework itself is manageable and fits into a normal maintenance round. It consists of four steps: put schedules on an unambiguous reference, take critical runs out of the window between 1 and 4 local time, secure the repeatability of the remaining runs, and update the rule set of the time zone database. The first step is the most effective. A scheduler that computes in Universal Time knows neither a doubled hour nor a gap, because Universal Time has neither. For a classic scheduler this is done via a time zone declaration in the table itself, for system timers via the calendar field. Whether a time zone declaration in the table is evaluated at all by the cron implementation in use is likewise stated in its manual page; where it is not, it remains an inert variable and the schedule keeps running in local time.
# Classic scheduler: set the time zone for the lines that follow
CRON_TZ=UTC
15 0 * * * /usr/local/bin/stock-sync --run-key=$(date -u +\%F)
30 1 * * * /usr/local/bin/dunning-run --once-per-day
45 2 * * * /usr/local/bin/document-numbers --lock
# System timer: calendar expression with an explicit time zone
[Timer]
OnCalendar=*-*-* 00:15:00 UTC
Persistent=true
RandomizedDelaySec=120
[Install]
WantedBy=timers.target
In the calendar expression the time zone is a field of its own: it can be specified as the literal string "UTC", the local timezone, or the timezone in the IANA timezone database format (systemd.time(7)). Without this declaration the system's local time applies – and with it the doubled hour. The second useful switch concerns missed runs: if it is set, the service unit is triggered immediately if it would have been triggered at least once during the time when the timer was inactive (systemd.timer(5)). That catches up runs which were missed while the timer was inactive, and for exactly that reason it requires the run to be repeatable – otherwise a missed run is traded for a duplicated one. The switch is no substitute for an unambiguous time specification: it addresses the inactivity of the timer, not the ambiguity of local time. This switch expressly only has an effect on timers configured with a calendar expression (systemd.timer(5)).
The fourth step is readily overlooked. The rules by which a system computes local time come from a continuously maintained database; its current release is 2026c, published on 8 July 2026 (IANA Time Zone Database). That maintenance is not an end in itself: this release alone records Alberta's move to a permanent offset on 18 June 2026 and Morocco's on 20 September 2026 (IANA Time Zone Database). End users typically receive updates to this data through their software and operating system vendors (IANA Time Zone Database) – on a server that means via package management, and thus via the update routine of the maintenance contract. A server whose time zone package has not moved for two years computes with old rules on the changeover days. What role this routine plays in the wider picture is shown by the overview of maintenance services.
The output of zdump is the quickest proof that a system knows the rules: it shows the cut on 25 October 2026 at 01:00 Universal Time and the jump of local time from 02:59:59 to 02:00:00. If that line is missing or names a different date, the rule set is outdated and everything else is moot. The third command answers the second question: which point in time does a calendar expression actually mean? Running it once for the critical schedules shows immediately which runs fall inside the doubled hour. Both checks belong in the same round as scheduling the maintenance window without revenue loss.
What is monitored during the night itself
Between 00:00 and 03:00 Universal Time a measurement regime of its own applies on this weekend. Not because more happens, but because the usual reference values do not hold for 60 minutes. Four observations are worth preparing and switching off again afterwards.
Run records per transaction key
Every nightly run writes one line with the calendar day and the transaction key. Two lines with the same key are direct proof of a duplicated run – without anyone having to compare business data.
Uniqueness errors in the database
Violations of unique keys rise sharply during the doubled hour when a run writes twice. This class of error is a precise early indicator and easy to filter in the logs.
Dispatch counts per recipient
Duplicated reminders, order confirmations or notices show up in dispatch statistics as two messages to the same address within one hour, long before anyone complains.
Clock offset of the system
Synchronisation with the reference time should remain inconspicuous across the changeover. A growing offset at exactly this point suggests a hardware clock kept in local time – a source of error that becomes visible only twice a year.
These four signals sensibly run into the same channel as the remaining operational messages, but as an alert class of their own, so they can be deactivated again after the weekend. How such a chain of log analysis and alerting is built is described in the article on log monitoring and alerting. Anyone who does not want to sit through the night themselves puts it on standby; the conditions for that are set out under monitoring and emergency support. And if something does visibly go wrong that night, customer communication decides how much damage is done – which is where the status page during outages fits in.
A schedule in local time is an appointment with a clock that changes its mind twice a year. If you move money at night, you are better off making that appointment with Universal Time.
Follow-up on Sunday and on Monday
On Sunday morning three questions need answering, in this order. First: did every scheduled run execute exactly once? The proof comes from the run record per calendar day, not from the feeling that no alerts arrived – a missed run typically produces no message at all. Second: are there transactions with two bookings, two documents or two messages within the doubled hour? A query over the period from 22:00 Universal Time on the previous day to 02:00 Universal Time, grouped by transaction, is enough for that. Third: do the day's metrics show anomalies that are explained by the extra hour alone? If so, that belongs in a footnote to the report, so that next quarter nobody hunts for a cause that does not exist.
Monday brings the dull but decisive part: whatever stood out that night is written down as a permanent change and not as a note for next time. Schedules still set in local time are converted. Runs that turned out not to be repeatable get a lock per transaction. The next changeover date – the last Sunday in March 2027 – moves into the same calendar as update and certificate deadlines. That is exactly what an SLA maintenance contract is for: it holds such recurring dates so they do not depend on individual memory. A related housekeeping task with the same pattern – recurring, inconspicuous, expensive when it goes wrong – is revoking access during offboarding.
Rework that fits into one morning
zdump -v Europe/Berlin | grep 2026 on every server, list all schedules between 1 and 4 local time, and convert the critical ones to Universal Time. In most installations that is a few hours of work and it holds for every future changeover. To anchor the check permanently in live operation, it belongs as a fixed item in the SLA maintenance contract; which services a running contract already covers is shown by the overview of maintenance packages.Sources and studies
zdump -v Europe/Berlin shows the transition on 25 October 2026 at 01:00 Universal Time, the rule set is current.Related Articles
Silent Job Failures: Monitoring Cron Jobs and Imports
Cron jobs and imports die quietly while the shop stays green. Set up heartbeat monitoring plus runtime and volume thresholds that catch half-finished runs.
Shop Server Logs: How Long IP Addresses May Be Stored
How long may IP addresses stay in server logs? What the GDPR requires, what the five weeks from the BfDI mean, and how rotation, truncation and backups fit in.
WordPress security updates: what old branches still get
WordPress 7.1.2 closed a critical flaw and the fix was backported to 4.7 as a courtesy. What older branches receive, what they do not, and when to move up.