[php-src] Issue #24735: DateTime::setTime() in the repeated hour of Europe/Dublin moves to the later occurrence (an hour ahead)
| From: | zoispag | Date: | Mon, 26 Oct 2026 09:38:06 +0000 |
| Subject: | [php-src] Issue #24735: DateTime::setTime() in the repeated hour of Europe/Dublin moves to the later occurrence (an hour ahead) | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-253210@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/24735
Author: zoispag
### Description
On the day clocks go back,
DateTime::setTime() on a time in the repeated hour in
Europe/Dublin moves it to the *second* occurrence of the wall time, an hour later, even
when the new time is only seconds away on the same wall clock. Europe/London, at the same instant
and with the same UTC offsets, keeps the first occurrence.
The following code:
```php
<?php
foreach (['Europe/Dublin', 'Europe/London', 'Europe/Amsterdam'] as
$tz) {
$d = (new DateTimeImmutable('2026-10-25 00:10:30 UTC'))->setTimezone(new
DateTimeZone($tz));
$e = $d->setTime((int) $d->format('H'), 10, 59);
printf("%-16s %s -> %s (%+ds)\n", $tz, $d->format('Y-m-d H:i:s T'),
$e->format('H:i:s T'), $e->getTimestamp() - $d->getTimestamp());
}
```
Resulted in this output:
```
Europe/Dublin 2026-10-25 01:10:30 IST -> 01:10:59 GMT (+3629s)
Europe/London 2026-10-25 01:10:30 BST -> 01:10:59 BST (+29s)
Europe/Amsterdam 2026-10-25 02:10:30 CEST -> 02:10:59 CEST (+29s)
```
But I expected this output instead:
```
Europe/Dublin 2026-10-25 01:10:30 IST -> 01:10:59 IST (+29s)
Europe/London 2026-10-25 01:10:30 BST -> 01:10:59 BST (+29s)
Europe/Amsterdam 2026-10-25 02:10:30 CEST -> 02:10:59 CEST (+29s)
```
Dublin and London both switch from UTC+1 to UTC+0 at 01:00 UTC on 25 October 2026, so I'd
expect them to behave the same. The difference seems to be that the tz database models Irish time
with a negative DST offset: IST (UTC+1) is the standard time and GMT is flagged as DST. So keeping
or choosing a DST state when resolving the ambiguous wall time gives the opposite result to every
other zone.
Anything that rounds a time with setTime(), modify('...') or
date libraries built on them (e.g. Carbon's endOfMinute()) is affected. We hit it
in production: Laravel's scheduler computed "end of the current minute" this way, so
during that hour each run waited an hour instead of seconds. That bug is being fixed on the Laravel
side (https://github.com/laravel/framework/pull/62197), but the root cause looks like it's
here.
### PHP Version
```
PHP 8.5.12 (cli) (built: Oct 19 2026 17:02:46) (ZTS)
timezone_version_get(): 2026.5
```
### Operating System
macOS, and Debian GNU/Linux 13 (trixie) with PHP 8.5.12 NTS