Description
getNextRunDate() skips an entire valid day for a daily midnight expression when the calculation starts on the spring DST transition day before the offset changes.
This appears related to #154 and #202, which were addressed by #203, but the midnight case below still fails on v3.6.0.
The scheduled local time itself is not inside the missing DST hour.
Reproduction
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use Cron\CronExpression;
$timezone = new DateTimeZone('Europe/Prague');
$current = new DateTimeImmutable(
'2026-03-29 00:30:00',
$timezone,
);
$next = (new CronExpression('0 0 * * *'))->getNextRunDate(
$current,
timeZone: $timezone->getName(),
);
echo $current->format('Y-m-d H:i:s P e') . PHP_EOL;
echo $next->format('Y-m-d H:i:s P e') . PHP_EOL;
Actual result
2026-03-29 00:30:00 +01:00 Europe/Prague
2026-03-31 00:00:00 +02:00 Europe/Prague
Expected result
2026-03-30 00:00:00 +02:00 Europe/Prague
The next valid occurrence after 2026-03-29 00:30:00 is midnight at the start of March 30. March 30 must not be skipped.
Failing PHPUnit test
public function testNextMidnightIsNotSkippedAcrossSpringDstTransition(): void
{
$timezone = new DateTimeZone('Europe/Prague');
$current = new DateTimeImmutable(
'2026-03-29 00:30:00',
$timezone,
);
$next = (new CronExpression('0 0 * * *'))->getNextRunDate(
$current,
timeZone: $timezone->getName(),
);
self::assertSame(
'2026-03-30 00:00:00 +02:00 Europe/Prague',
$next->format('Y-m-d H:i:s P e'),
);
}
Environment
dragonmantank/cron-expression: v3.6.0
- PHP:
8.3.6
- Timezone:
Europe/Prague
- PHP timezone database:
0.system
- Also reproducible on current master: d425a24
Relation to PR #203
PR #203 fixes the reproductions from #154 and #202 on v3.6.0. I verified that those original cases now work.
This reproduction is slightly different: the target hour is midnight, before the DST turnover hour, and the calculation begins on the transition day before the offset changes. In this case, the first midnight after the transition is still skipped.
Description
getNextRunDate()skips an entire valid day for a daily midnight expression when the calculation starts on the spring DST transition day before the offset changes.This appears related to #154 and #202, which were addressed by #203, but the midnight case below still fails on v3.6.0.
The scheduled local time itself is not inside the missing DST hour.
Reproduction
Actual result
Expected result
The next valid occurrence after
2026-03-29 00:30:00is midnight at the start of March 30. March 30 must not be skipped.Failing PHPUnit test
Environment
dragonmantank/cron-expression:v3.6.08.3.6Europe/Prague0.systemRelation to PR #203
PR #203 fixes the reproductions from #154 and #202 on v3.6.0. I verified that those original cases now work.
This reproduction is slightly different: the target hour is midnight, before the DST turnover hour, and the calculation begins on the transition day before the offset changes. In this case, the first midnight after the transition is still skipped.