Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nextExecution over daylight savings is wrong #61

Closed
swanke00 opened this issue Dec 19, 2015 · 7 comments
Closed

nextExecution over daylight savings is wrong #61

swanke00 opened this issue Dec 19, 2015 · 7 comments

Comments

@swanke00
Copy link

I want to schedule something to run every day at 17:00. Cron tab is "0 17 * * *". When the nextExecution crosses daylight savings time, the hour is 18:00 (or 16:00 during fall back). Here's my code:

    CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX));
    // daily at 17:00
    ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 17 * * *"));
    // Daylight savings for New York 2016 is Mar 13 at 2am
    DateTime last = new DateTime(2016, 3, 12, 17, 0, DateTimeZone.forID("America/New_York"));
    DateTime next = executionTime.nextExecution(last);

    long millis = next.getMillis() - last.getMillis();
    System.out.println("Last = " + last + ", Next Execution = " + next + ", diff = " + (millis / 3600000));

.. and the output is :

Last = 2016-03-12T17:00:00.000-05:00, Next Execution = 2016-03-13T18:00:00.000-04:00, diff = 24

Note: the next execution time is 18:00 instead of 17:00 and the time difference is 24 hours when it should be 23. When I run with November dates, the next execution hour is 16 and the diff is 24 hours instead of 25.

@jmrozanec
Copy link
Owner

@swanke00 Thank you for reporting this. Contributions are welcome!

@swanke00
Copy link
Author

Adding to this issue. lastExecution() is also incorrect.
CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX));
// daily at 17:00
ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 17 * * *"));
// Daylight savings for New York 2016 is Mar 13 at 2am
DateTime now = new DateTime(2016, 3, 12, 17, 0, DateTimeZone.forID("America/Phoenix"));
DateTime next = executionTime.nextExecution(now);
DateTime last = executionTime.lastExecution(now);

    long millis = now.getMillis() - last.getMillis();
    System.out.println("Now  = " + now + ",\nLast = " + last + ",\nNext = " + next + ",\ndiff = "
            + (millis / 3600000));

the output is

Now = 2016-03-12T17:00:00.000-07:00,
Last = 2016-03-11T17:00:00.000-05:00,
Next = 2016-03-13T17:00:00.000-07:00,
diff = 26

Note the UTC offset of -5:00 which is my local timezone offset and a time difference of 26 hours due to the incorrect zone offset.

@jmrozanec
Copy link
Owner

@swanke00 thank you! If you have some time, would you write a test case for this? Be well!

@DanoOM
Copy link
Contributor

DanoOM commented Mar 15, 2016

cron-utils version 3.1.5
We ran into this on the last day light saving adjustment..
Starting at exactly 2:00am, all schedules were off by 1 hour, and it did not correct until 2/13 midnight.

Here is a code snippet, you can run prints out the runtimes for this cron expression: * 0/2 * * * ?
`
package test;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

import com.cronutils.model.Cron;
import com.cronutils.model.CronType;
import com.cronutils.model.definition.CronDefinition;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.model.time.ExecutionTime;
import com.cronutils.parser.CronParser;

import org.joda.time.DateTime;

public class BadDayLightSavings {

public static void BadDayLightSavings() {
    try {
        String expression = "* 0/2 * * * ?";
        Date startDate;        
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy MM dd HH:mm:ss");
        startDate = sdf.parse("2016 03 13 00:00:59");

        Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        cal.setTime(startDate);
        CronDefinition cronDef = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
        CronParser parser = new CronParser(cronDef);
        Cron cron = parser.parse(expression);
        DateTime currentTime = new DateTime(startDate);
        ExecutionTime executionTime = ExecutionTime.forCron(cron);
        int count = 24 * 60;
        for (int i = 0 ;i < count; i++) {
            // At daylight savings time: 02:00AM nextExecution advances 1 hour each time, until midnight
            DateTime nextRun = executionTime.nextExecution(currentTime);
            System.out.println("Scheduled At:" +currentTime.toDate()+ " NEXT RUN:" + nextRun.toDate());
            // do not reschedule for same minute
            while(currentTime.isBefore(nextRun)) {
                currentTime = currentTime.plusMinutes(1);
            }
        }        
    }
    catch(Exception e) {
        e.printStackTrace();
    }
}

}
`

@jmrozanec
Copy link
Owner

@DanoOM Thank you! Wouldn't you mind to turn this example into a test case for this issue? I will be eager to accept such a pull request.

@jmrozanec
Copy link
Owner

@DanoOM @swanke00 issue fixed!

@jmrozanec
Copy link
Owner

@swanke00 @DanoOM New version released! Please check details here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants