TL; DR
In Quartz 1 you can use this cron: 59 59 23 31 12? 2099 59 59 23 31 12? 2099 59 59 23 31 12? 2099 59 59 23 31 12? 2099 (last valid date).
In Quartz 2, can you use this cron: 0 0 0 1 1? 2200 0 0 0 1 1? 2200 0 0 0 1 1? 2200 0 0 0 1 1? 2200
Using an expression far in the future
Made some quick tests using org.quartz.CronExpression .
String exp = "0 0 0 1 1 ? 3000"; boolean valid = CronExpression.isValidExpression(exp); System.out.println(valid); if (valid) { CronExpression cronExpression = new CronExpression(exp); System.out.println(cronExpression.getNextValidTimeAfter(new Date())); }
When do I do String exp = "# 0 0 0 1 1?"; , the isValid test returns false .
With the example above, the result is as follows:
true null
Meaning:
- expression is valid;
- There is no upcoming date that matches this expression.
However, in order for the scheduler to accept the cron trigger, the latter must correspond to a date in the future.
I tried for several years and realized that when the year exceeds 2300, Quartz seems to no longer bother (although I did not find mention of the maximum value for the year in the Quartz 2 documentation ). There may be a cleaner way to do this, but it will satisfy my needs at the moment.
So, in the end, the cron offered to me is - 0 0 0 1 1? 2200 0 0 0 1 1? 2200 0 0 0 1 1? 2200 0 0 0 1 1? 2200
Quartz 1 option
Please note that in Quartz 1, 2099 is the last valid year . So you can adapt your cron expression to use the Maciej Matys clause : 59 59 23 31 12? 2099 59 59 23 31 12? 2099 59 59 23 31 12? 2099 59 59 23 31 12? 2099
Alternative: use date in the past
Arno Denoyel suggested something more elegant, which my test confirms above as the correct expression: instead of choosing a date in the distant future, select it in the distant past:
0 0 0 1 1? 1970 0 0 0 1 1? 1970 0 0 0 1 1? 1970 0 0 0 1 1? 1970 (first valid expression according to Quartz documentation).
This solution does not work though.
hippofluff emphasized that Quartz will detect that an expression in the past will never be executed again, and therefore throws an exception.
org.quartz.SchedulerException: Based on configured schedule, the given trigger will never fire.
It seems to have been in Quartz for a long time .
Lessons learned: the test is not reliable, as is
This underscores the weakness of my test: if you want to test CronExpression , remember that it must have nextValidTime 1 . Otherwise, the scheduler to which you pass it will simply reject it with the above exception.
I would advise you to adapt the test code as follows:
String exp = "0 0 0 1 1 ? 3000"; boolean valid = CronExpression.isValidExpression(exp); if (valid) { CronExpression cronExpression = new CronExpression(exp); valid = cronExpression.getNextValidTimeAfter(new Date()) != null; } System.out.println("Can I use <" + exp + ">? " + (valid ? "Go ahead!" : "This shall fail."));
There you go: no need to think, just read the conclusion.
1 This is the part that I forgot when I tested the Arnaud solution, making me a fool and proving that my test was not proof for me.