Skip to content

The time of daylight saving time parsed by CronExpression is completely skipped #36859

@zzquq

Description

@zzquq

Bug Report

In the Cairo time zone of Egypt, for tasks that are executed every 2 hours, I use CronExpression to calculate the future time points to be executed and output them to verify if the execution time is correct. I found that on the day of entering daylight saving time, the time calculated by CronExpression completely skipped the day of 2025-04-25T00:00+03:00 [Africa/Cairo].

It was ultimately discovered that when entering daylight saving time, if the clock time is directly adjusted from 00:00 to 01:00, the day will be completely skipped. If the United States adjusts from 02:00 to 03:00, then this day is normal.

Program

public static void main(String[] args) {
        TimeZone.setDefault(TimeZone.getTimeZone("Africa/Cairo"));
        long startTs = 1745521820000L; // 2025-04-24 21:10:20

        var springExpr = org.springframework.scheduling.support.CronExpression.parse("0 0 */2 * * ?");
        ZonedDateTime springDt = ZonedDateTime.ofInstant(Instant.ofEpochMilli(startTs), TimeZone.getDefault().toZoneId());

        for (int i = 1; i <= 20; i++) {

            ZonedDateTime springNext = springExpr.next(springDt);
            long springTs = springNext != null ? springNext.toInstant().toEpochMilli() : -1;
            System.out.println(springNext + " | " +springTs);
            springDt = springNext;
        }
    }
2025-04-24T22:00+02:00[Africa/Cairo] | 1745524800000
2025-04-26T00:00+03:00[Africa/Cairo] | 1745614800000
2025-04-26T02:00+03:00[Africa/Cairo] | 1745622000000
2025-04-26T04:00+03:00[Africa/Cairo] | 1745629200000
2025-04-26T06:00+03:00[Africa/Cairo] | 1745636400000

But switching to the US time zone is normal.

        TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
        Date date = new Date(1741400000000L);

        org.springframework.scheduling.support.CronExpression expression = org.springframework.scheduling.support.CronExpression.parse("0 0 */2 * * ?");
        ZonedDateTime dateTime = ZonedDateTime.ofInstant(date.toInstant(), TimeZone.getDefault().toZoneId());
        for (int i = 1; i <= 100; i++) {
            ZonedDateTime nextTime = expression.next(dateTime);
            java.util.Date nextDate = java.util.Date.from(nextTime.toInstant());
            System.out.println( i + ": " + nextDate + "  |  " + nextDate.getTime());
            dateTime = nextTime;
        }
1: Sat Mar 07 23:00:00 PST 2026  |  1772953200000
2: Sun Mar 08 01:00:00 PST 2026  |  1772960400000
3: Sun Mar 08 03:00:00 PDT 2026  |  1772964000000
4: Sun Mar 08 05:00:00 PDT 2026  |  1772971200000
5: Sun Mar 08 07:00:00 PDT 2026  |  1772978400000
6: Sun Mar 08 09:00:00 PDT 2026  |  1772985600000

Version information

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.31</version>
        </dependency>

Upgrading to 6.2.28 can also reproduce

Metadata

Metadata

Assignees

No one assigned

    Labels

    in: coreIssues in core modules (aop, beans, core, context, expression)status: waiting-for-triageAn issue we've not yet triaged or decided on

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions