jmrozanec / cron-utils Goto Github PK
View Code? Open in Web Editor NEWCron utils for parsing, validations and human readable descriptions as well as date/time interoperability.
Home Page: http://cron-utils.com
License: Apache License 2.0
Cron utils for parsing, validations and human readable descriptions as well as date/time interoperability.
Home Page: http://cron-utils.com
License: Apache License 2.0
With this CronDefinition:
CronDefinitionBuilder.defineCron()
.withMinutes().and()
.withHours().and()
.withDayOfMonth()
.supportsL().supportsW()
.and()
.withMonth().and()
.withDayOfWeek()
.withMondayDoWValue(1)
.withValidRange(1, 7)
.supportsHash().supportsL()
.and()
.withYear().and()
.lastFieldOptional()
and this cron expression:
"30 3 * * MON-FRI"
executionTime.nextExecution(1970-01-01....)
returns 1970-01-02... instead of 1970-01-01. It seems to always do this on when the first day of the month falls within the DoW range. It looks like an initial case type bug. The BetweenDayOfWeekValueGenerator will never return the value 1 in this case - only the value 8.
The result is that if I execute this over the year of 1970, I'd expect to get 261 days. Instead I get 245 days.
Based on this bug for the year 1970, I'd expect to lose 8 days. I'm losing 16 days though. Taking a quick look at the output, it appears the same issue exists for the last day of the month when the last day falls within the DoW range. For example, cron-utils will not return 1970-07-31 (a Friday) for the above cron expression.
As from documentation, LW value is supported at Quartz, but not at cron-utils yet.
Documentation available here
Sorry for scala, but it should be pretty clear:
object CronError extends App {
val cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX)
val cron = new CronParser(CronSchedule.cronDefinition).parse("0 */2 * * * *")
val executionTime = ExecutionTime.forCron(cron)
val time = DateTime.parse("2015-09-05T13:56:00.000-07:00")
val next = executionTime.nextExecution(time)
val shouldBeInNextHour = executionTime.nextExecution(next)
val text = CronDescriptor.instance(Locale.US).describe(cron)
println(s"Schedule: $text")
println(s"Original time: $time")
println(s"Next event time: $next")
println(s"It should be in next hour: $shouldBeInNextHour")
}
Library version: 3.1.0
PS. at the same time pattern "0 */1 * * * *" works fine.
Hello, if I'm not wrong the Cron4j definition is wrong for "Every X times" crons.
In Cron4J Manual (http://goo.gl/2CgX2h) to have a task execute every 5 minutes you use:
***/5 * * * ***
And to have the task execute at XX:05 you use:
**5 * * * ***
Now there seems to be some special case in between which Cron4J supports but its not documented anywhere nor I found it in the manuals and examples of Cron4J and its this one:
**/5 * * * ***
_BUG:_
Cron-Utils interprets "/5 * * * *" as "Every 5 minutes" but in Cron4J it is being interpreted as "once a hour at 05min".
Now this gets even worse with the Cron-Utils mapper. As it maps any "/x" and "/x" to "/x". So even if you map from CRON4J to CRON4J it breaks each cron string removing the "" having a unexpected result.
Here is a demo code:
public static void main(String[] args) {
// Cron Definitions & Parsers
CronDefinition unixCronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX);
CronDefinition cron4jCronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.CRON4J);
CronParser unixParser = new CronParser(unixCronDefinition);
CronParser cron4jParser = new CronParser(unixCronDefinition);
// From UNIX to CRON4J Mapper
CronMapper cronMapper = new CronMapper(unixCronDefinition, cron4jCronDefinition);
// ISSUE 1: Every X times BUG for CRON4J
System.out.println(cronMapper.map(unixParser.parse("*/5 * * * *")).asString()); // WRONG - /5 * * * * (Should be */5 * * * *)
System.out.println(cronMapper.map(unixParser.parse("/5 * * * *")).asString()); // WRONG - /5 * * * * (Should be */5 * * * *)
System.out.println(cronMapper.map(unixParser.parse("5 * * * *")).asString()); // OK - 5 * * * *
// Descriptor
CronDescriptor descriptor = CronDescriptor.instance(Locale.UK);
System.out.println(descriptor.describe(cron4jParser.parse("*/5 * * * *"))); // OK - every 5 minutes
System.out.println(descriptor.describe(cron4jParser.parse("/5 * * * *"))); // WRONG - every 5 minutes (Should be "every hour at minute 5")
System.out.println(descriptor.describe(cron4jParser.parse("5 * * * *"))); // OK - every hour at minute 5
// ISSUE 2: (Not so important)
// This is not supported by Cron-Utils
// In Cron4J Manual http://www.sauronsoftware.it/projects/cron4j/manual.php
System.out.println(descriptor.describe(cron4jParser.parse("0 5 * * *|8 10 * * *|22 17 * * *")));
System.out.println(cronMapper.map(unixParser.parse("0 5 * * *|8 10 * * *|22 17 * * *")).asString());
}
Basically the only thing missing here is that Cron-Utils shouls add a "/x" to the evey x times definition. And to parse "/x" the same as "x" and not as "/x".
Thanks for the awesome work done so far. Cron-Utils is just awesome useful.
This code:
CronDefinition definition = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
CronParser parser = new CronParser(definition);
Cron cron = parser.parse("0/1 * * 1/1 * ? *"); // Every 1 second
ExecutionTime executionTime = ExecutionTime.forCron(cron);
DateTime now = new DateTime().withTime(23, 59, 59, 0);
DateTime nextExecution = executionTime.nextExecution(now);
Would throw this exception: org.joda.time.IllegalFieldValueException: Value 24 for hourOfDay must be in the range [0,23]
because 23:59:59 + 1 second would become 24:00:00, which is an invalid hour for a new DateTime
object.
For the cron expression 0/30 * * * * *, with a custom definition of:
// Unix Crontab with seconds allowed
CronDefinition cronDefinition = CronDefinitionBuilder.defineCron()
.withSeconds().and()
.withMinutes().and()
.withHours().and()
.withDayOfMonth().and()
.withMonth().and()
.withDayOfWeek().withValidRange(0, 7).withMondayDoWValue(1).withIntMapping(7, 0).and()
.instance();
Performing a nextExecution call when the input DateTime value is between 30 and 59 seconds of the minute causes the method to return with a DateTime at the previous minute instead of the next minute.
For example:
nextExecution('2015-08-28 12:05:44') -> 2015-08-28 12:05:00
nextExecution('2015-08-28 12:05:14') -> 2015-08-28 12:05:30
Note that I've also tried this with '*/30 * * * * *' and got the same results.
Unit tests:
@Test
public void testCronExpressionAfterHalf() {
CronDefinition cronDefinition = CronDefinitionBuilder.defineCron()
.withSeconds().and()
.withMinutes().and()
.withHours().and()
.withDayOfMonth().and()
.withMonth().and()
.withDayOfWeek().withValidRange(0, 7).withMondayDoWValue(1).withIntMapping(7, 0).and()
.instance();
CronParser parser = new CronParser(cronDefinition);
Cron cron = parser.parse("*/30 * * * * *");
MutableDateTime mutableDateTime = new MutableDateTime();
mutableDateTime.setDateTime(2015, 8, 28, 12, 5, 44, 0);
DateTime startDateTime = mutableDateTime.toDateTime();
mutableDateTime = new MutableDateTime();
mutableDateTime.setDateTime(2015, 8, 28, 12, 6, 0, 0);
DateTime expectedDateTime = mutableDateTime.toDateTime();
ExecutionTime executionTime = ExecutionTime.forCron(cron);
DateTime nextExecutionDateTime = executionTime.nextExecution(startDateTime);
MatcherAssert.assertThat(nextExecutionDateTime, Matchers.equalTo(expectedDateTime));
}
@Test
public void testCronExpressionBeforeHalf() {
CronDefinition cronDefinition = CronDefinitionBuilder.defineCron()
.withSeconds().and()
.withMinutes().and()
.withHours().and()
.withDayOfMonth().and()
.withMonth().and()
.withDayOfWeek().withValidRange(0, 7).withMondayDoWValue(1).withIntMapping(7, 0).and()
.instance();
CronParser parser = new CronParser(cronDefinition);
Cron cron = parser.parse("0/30 * * * * *");
MutableDateTime mutableDateTime = new MutableDateTime();
mutableDateTime.setDateTime(2015, 8, 28, 12, 5, 14, 0);
DateTime startDateTime = mutableDateTime.toDateTime();
mutableDateTime = new MutableDateTime();
mutableDateTime.setDateTime(2015, 8, 28, 12, 5, 30, 0);
DateTime expectedDateTime = mutableDateTime.toDateTime();
ExecutionTime executionTime = ExecutionTime.forCron(cron);
DateTime nextExecutionDateTime = executionTime.nextExecution(startDateTime);
MatcherAssert.assertThat(nextExecutionDateTime, Matchers.equalTo(expectedDateTime));
}
Hello,
I just started using your library and noticed a typo in the README.md file.
On line:
//Get date for next execution
DateTime nextExecution = executionTime.timeToNextExecution(now));
Should be:
//Get date for next execution
DateTime nextExecution = executionTime.nextExecution(now));
Hope it helps.
Quartz does not support specifying both a day-of-week and a day-of-month value (you must currently use the '?' character in one of these fields).
For example: 0 0 0 * * 1 * is not legal in quartz, instead it must be: 0 0 0 ? * 1 *
Code such as:
CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX);
CronDefinition quartzDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
CronMapper cronMapper = new CronMapper(cronDefinition, quartzDefinition);
CronParser cronParser = new CronParser(cronDefinition);
Cron cronCron = cronParser.parse(cronString);
Cron quartzCron = cronMapper.map(cronCron);
String result = quartzCron.asString();
Will take 0 0/2 * * * and produce 0 /2 * * * * - it should be 0 /2 * * ? * (or possibly 0 /2 ? * * *)
Using quartz 2.2.2 and cron-utils 3.1.2
0 0 0 1 1 ?
at 00:00 at 1 day at January month
0/1 * * * * ?
every seconds
https://github.com/RedHogs/cron-parser seems to be doing a way better job...
I'm trying to translate a UNIX cron expression to Quartz cron expression. This is how I'm trying to do so (Groovy code):
Cron unixCron = new CronParser(new CronDefinitionBuilder().instanceDefinitionFor(CronType.UNIX)).parse('* * * * *')
CronMapper cronMapper = new CronMapper(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX), CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ))
Cron quartzCron = cronMapper.map(unixCron)
String quartzCronExpression = quartzCron.asString()
However, * * * * *
gets translated to 0 * * * * * *
which is not valid (I think it should be 0 * * * * * ?
). Is this a bug (or unsupported feature) or is my translation code wrong?
Thanks for your help.
I'm trying a simple unix crontab "* * * * 1", which should run every minute of every hour Mondays in every month, but nextExecution doesn't seem give the correct result. Following is the code:
crontab = "* * * * 1";
CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX);
CronParser parser = new CronParser(cronDefinition);
Cron cron = parser.parse(crontab);
DateTime date = DateTime.now();
System.out.println("now:" + date);
ExecutionTime executionTime = ExecutionTime.forCron(cron);
DateTime nextExecution = executionTime.nextExecution(date);
DateTime lastExecution = executionTime.lastExecution(date);
System.out.println("next execution:" + nextExecution);
System.out.println("last execution:" + lastExecution);
Output:
now:2015-10-13T17:26:54.468-07:00
next execution:2015-11-02T00:00:00.000-08:00
last execution:2015-10-05T23:59:00.000-07:00
The last execution time seems correct, but next execution time should be 2015-10-19T00:00:00.000-07:00. It skips two weeks and also change the time zone. Can you guys take a look at it?
Thanks,
Jun
Test File : https://gist.github.com/rtennantventuretech/3e201c854b3546bed2e7
Test output
TEST1 - expecting 0 instants
instants.size() == 0
instants: []
TEST2 - expecting 12 instants
instants.size() == 12
instants: [1970-01-31T18:00:00.000Z, 1970-02-28T18:00:00.000Z, 1970-03-31T18:00:00.000Z, 1970-04-30T17:00:00.000Z, 1970-05-31T17:00:00.000Z, 1970-06-30T17:00:00.000Z, 1970-07-31T17:00:00.000Z, 1970-08-31T17:00:00.000Z, 1970-09-30T17:00:00.000Z, 1970-10-31T18:00:00.000Z, 1970-11-30T18:00:00.000Z, 1970-12-31T18:00:00.000Z]
TEST1 - expecting 0 instants
instants.size() == 1
instants: [1970-01-02T06:00:00.000Z]
java.lang.AssertionError: expected [0] but found [1]
Expected :0
Actual :1
TEST2 - expecting 12 instants
Uh Oh! Next == Previous
instants.size() == 298
instants: [1970-01-01T18:00:00.000Z, 1970-01-02T18:00:00.000Z, 1970-01-03T18:00:00.000Z, 1970-01-04T18:00:00.000Z, 1970-01-05T18:00:00.000Z, 1970-01-06T18:00:00.000Z, 1970-01-07T18:00:00.000Z, 1970-01-08T18:00:00.000Z, 1970-01-09T18:00:00.000Z, 1970-01-10T18:00:00.000Z, 1970-01-11T18:00:00.000Z, 1970-01-12T18:00:00.000Z, 1970-01-13T18:00:00.000Z, 1970-01-14T18:00:00.000Z, 1970-01-15T18:00:00.000Z, 1970-01-16T18:00:00.000Z, 1970-01-17T18:00:00.000Z, 1970-01-18T18:00:00.000Z, 1970-01-19T18:00:00.000Z, 1970-01-20T18:00:00.000Z, 1970-01-21T18:00:00.000Z, 1970-01-22T18:00:00.000Z, 1970-01-23T18:00:00.000Z, 1970-01-24T18:00:00.000Z, 1970-01-25T18:00:00.000Z, 1970-01-26T18:00:00.000Z, 1970-01-27T18:00:00.000Z, 1970-01-28T18:00:00.000Z, 1970-01-29T18:00:00.000Z, 1970-01-30T18:00:00.000Z, 1970-01-31T18:00:00.000Z, 1970-02-01T18:00:00.000Z, 1970-02-02T18:00:00.000Z, 1970-02-03T18:00:00.000Z, 1970-02-04T18:00:00.000Z, 1970-02-05T18:00:00.000Z, 1970-02-06T18:00:00.000Z, 1970-02-07T18:00:00.000Z, 1970-02-08T18:00:00.000Z, 1970-02-09T18:00:00.000Z, 1970-02-10T18:00:00.000Z, 1970-02-11T18:00:00.000Z, 1970-02-12T18:00:00.000Z, 1970-02-13T18:00:00.000Z, 1970-02-14T18:00:00.000Z, 1970-02-15T18:00:00.000Z, 1970-02-16T18:00:00.000Z, 1970-02-17T18:00:00.000Z, 1970-02-18T18:00:00.000Z, 1970-02-19T18:00:00.000Z, 1970-02-20T18:00:00.000Z, 1970-02-21T18:00:00.000Z, 1970-02-22T18:00:00.000Z, 1970-02-23T18:00:00.000Z, 1970-02-24T18:00:00.000Z, 1970-02-25T18:00:00.000Z, 1970-02-26T18:00:00.000Z, 1970-02-27T18:00:00.000Z, 1970-02-28T18:00:00.000Z, 1970-03-01T18:00:00.000Z, 1970-03-02T18:00:00.000Z, 1970-03-03T18:00:00.000Z, 1970-03-04T18:00:00.000Z, 1970-03-05T18:00:00.000Z, 1970-03-06T18:00:00.000Z, 1970-03-07T18:00:00.000Z, 1970-03-08T18:00:00.000Z, 1970-03-09T18:00:00.000Z, 1970-03-10T18:00:00.000Z, 1970-03-11T18:00:00.000Z, 1970-03-12T18:00:00.000Z, 1970-03-13T18:00:00.000Z, 1970-03-14T18:00:00.000Z, 1970-03-15T18:00:00.000Z, 1970-03-16T18:00:00.000Z, 1970-03-17T18:00:00.000Z, 1970-03-18T18:00:00.000Z, 1970-03-19T18:00:00.000Z, 1970-03-20T18:00:00.000Z, 1970-03-21T18:00:00.000Z, 1970-03-22T18:00:00.000Z, 1970-03-23T18:00:00.000Z, 1970-03-24T18:00:00.000Z, 1970-03-25T18:00:00.000Z, 1970-03-26T18:00:00.000Z, 1970-03-27T18:00:00.000Z, 1970-03-28T18:00:00.000Z, 1970-03-29T18:00:00.000Z, 1970-03-30T18:00:00.000Z, 1970-03-31T18:00:00.000Z, 1970-04-01T18:00:00.000Z, 1970-04-02T18:00:00.000Z, 1970-04-03T18:00:00.000Z, 1970-04-04T18:00:00.000Z, 1970-04-05T18:00:00.000Z, 1970-04-06T18:00:00.000Z, 1970-04-07T18:00:00.000Z, 1970-04-08T18:00:00.000Z, 1970-04-09T18:00:00.000Z, 1970-04-10T18:00:00.000Z, 1970-04-11T18:00:00.000Z, 1970-04-12T18:00:00.000Z, 1970-04-13T18:00:00.000Z, 1970-04-14T18:00:00.000Z, 1970-04-15T18:00:00.000Z, 1970-04-16T18:00:00.000Z, 1970-04-17T18:00:00.000Z, 1970-04-18T18:00:00.000Z, 1970-04-19T18:00:00.000Z, 1970-04-20T18:00:00.000Z, 1970-04-21T18:00:00.000Z, 1970-04-22T18:00:00.000Z, 1970-04-23T18:00:00.000Z, 1970-04-24T18:00:00.000Z, 1970-04-25T18:00:00.000Z, 1970-04-26T18:00:00.000Z, 1970-04-27T17:00:00.000Z, 1970-04-28T17:00:00.000Z, 1970-04-29T17:00:00.000Z, 1970-04-30T17:00:00.000Z, 1970-05-01T17:00:00.000Z, 1970-05-02T17:00:00.000Z, 1970-05-03T17:00:00.000Z, 1970-05-04T17:00:00.000Z, 1970-05-05T17:00:00.000Z, 1970-05-06T17:00:00.000Z, 1970-05-07T17:00:00.000Z, 1970-05-08T17:00:00.000Z, 1970-05-09T17:00:00.000Z, 1970-05-10T17:00:00.000Z, 1970-05-11T17:00:00.000Z, 1970-05-12T17:00:00.000Z, 1970-05-13T17:00:00.000Z, 1970-05-14T17:00:00.000Z, 1970-05-15T17:00:00.000Z, 1970-05-16T17:00:00.000Z, 1970-05-17T17:00:00.000Z, 1970-05-18T17:00:00.000Z, 1970-05-19T17:00:00.000Z, 1970-05-20T17:00:00.000Z, 1970-05-21T17:00:00.000Z, 1970-05-22T17:00:00.000Z, 1970-05-23T17:00:00.000Z, 1970-05-24T17:00:00.000Z, 1970-05-25T17:00:00.000Z, 1970-05-26T17:00:00.000Z, 1970-05-27T17:00:00.000Z, 1970-05-28T17:00:00.000Z, 1970-05-29T17:00:00.000Z, 1970-05-30T17:00:00.000Z, 1970-05-31T17:00:00.000Z, 1970-06-01T17:00:00.000Z, 1970-06-02T17:00:00.000Z, 1970-06-03T17:00:00.000Z, 1970-06-04T17:00:00.000Z, 1970-06-05T17:00:00.000Z, 1970-06-06T17:00:00.000Z, 1970-06-07T17:00:00.000Z, 1970-06-08T17:00:00.000Z, 1970-06-09T17:00:00.000Z, 1970-06-10T17:00:00.000Z, 1970-06-11T17:00:00.000Z, 1970-06-12T17:00:00.000Z, 1970-06-13T17:00:00.000Z, 1970-06-14T17:00:00.000Z, 1970-06-15T17:00:00.000Z, 1970-06-16T17:00:00.000Z, 1970-06-17T17:00:00.000Z, 1970-06-18T17:00:00.000Z, 1970-06-19T17:00:00.000Z, 1970-06-20T17:00:00.000Z, 1970-06-21T17:00:00.000Z, 1970-06-22T17:00:00.000Z, 1970-06-23T17:00:00.000Z, 1970-06-24T17:00:00.000Z, 1970-06-25T17:00:00.000Z, 1970-06-26T17:00:00.000Z, 1970-06-27T17:00:00.000Z, 1970-06-28T17:00:00.000Z, 1970-06-29T17:00:00.000Z, 1970-06-30T17:00:00.000Z, 1970-07-01T17:00:00.000Z, 1970-07-02T17:00:00.000Z, 1970-07-03T17:00:00.000Z, 1970-07-04T17:00:00.000Z, 1970-07-05T17:00:00.000Z, 1970-07-06T17:00:00.000Z, 1970-07-07T17:00:00.000Z, 1970-07-08T17:00:00.000Z, 1970-07-09T17:00:00.000Z, 1970-07-10T17:00:00.000Z, 1970-07-11T17:00:00.000Z, 1970-07-12T17:00:00.000Z, 1970-07-13T17:00:00.000Z, 1970-07-14T17:00:00.000Z, 1970-07-15T17:00:00.000Z, 1970-07-16T17:00:00.000Z, 1970-07-17T17:00:00.000Z, 1970-07-18T17:00:00.000Z, 1970-07-19T17:00:00.000Z, 1970-07-20T17:00:00.000Z, 1970-07-21T17:00:00.000Z, 1970-07-22T17:00:00.000Z, 1970-07-23T17:00:00.000Z, 1970-07-24T17:00:00.000Z, 1970-07-25T17:00:00.000Z, 1970-07-26T17:00:00.000Z, 1970-07-27T17:00:00.000Z, 1970-07-28T17:00:00.000Z, 1970-07-29T17:00:00.000Z, 1970-07-30T17:00:00.000Z, 1970-07-31T17:00:00.000Z, 1970-08-01T17:00:00.000Z, 1970-08-02T17:00:00.000Z, 1970-08-03T17:00:00.000Z, 1970-08-04T17:00:00.000Z, 1970-08-05T17:00:00.000Z, 1970-08-06T17:00:00.000Z, 1970-08-07T17:00:00.000Z, 1970-08-08T17:00:00.000Z, 1970-08-09T17:00:00.000Z, 1970-08-10T17:00:00.000Z, 1970-08-11T17:00:00.000Z, 1970-08-12T17:00:00.000Z, 1970-08-13T17:00:00.000Z, 1970-08-14T17:00:00.000Z, 1970-08-15T17:00:00.000Z, 1970-08-16T17:00:00.000Z, 1970-08-17T17:00:00.000Z, 1970-08-18T17:00:00.000Z, 1970-08-19T17:00:00.000Z, 1970-08-20T17:00:00.000Z, 1970-08-21T17:00:00.000Z, 1970-08-22T17:00:00.000Z, 1970-08-23T17:00:00.000Z, 1970-08-24T17:00:00.000Z, 1970-08-25T17:00:00.000Z, 1970-08-26T17:00:00.000Z, 1970-08-27T17:00:00.000Z, 1970-08-28T17:00:00.000Z, 1970-08-29T17:00:00.000Z, 1970-08-30T17:00:00.000Z, 1970-08-31T17:00:00.000Z, 1970-09-01T17:00:00.000Z, 1970-09-02T17:00:00.000Z, 1970-09-03T17:00:00.000Z, 1970-09-04T17:00:00.000Z, 1970-09-05T17:00:00.000Z, 1970-09-06T17:00:00.000Z, 1970-09-07T17:00:00.000Z, 1970-09-08T17:00:00.000Z, 1970-09-09T17:00:00.000Z, 1970-09-10T17:00:00.000Z, 1970-09-11T17:00:00.000Z, 1970-09-12T17:00:00.000Z, 1970-09-13T17:00:00.000Z, 1970-09-14T17:00:00.000Z, 1970-09-15T17:00:00.000Z, 1970-09-16T17:00:00.000Z, 1970-09-17T17:00:00.000Z, 1970-09-18T17:00:00.000Z, 1970-09-19T17:00:00.000Z, 1970-09-20T17:00:00.000Z, 1970-09-21T17:00:00.000Z, 1970-09-22T17:00:00.000Z, 1970-09-23T17:00:00.000Z, 1970-09-24T17:00:00.000Z, 1970-09-25T17:00:00.000Z, 1970-09-26T17:00:00.000Z, 1970-09-27T17:00:00.000Z, 1970-09-28T17:00:00.000Z, 1970-09-29T17:00:00.000Z, 1970-09-30T17:00:00.000Z, 1970-10-01T17:00:00.000Z, 1970-10-02T17:00:00.000Z, 1970-10-03T17:00:00.000Z, 1970-10-04T17:00:00.000Z, 1970-10-05T17:00:00.000Z, 1970-10-06T17:00:00.000Z, 1970-10-07T17:00:00.000Z, 1970-10-08T17:00:00.000Z, 1970-10-09T17:00:00.000Z, 1970-10-10T17:00:00.000Z, 1970-10-11T17:00:00.000Z, 1970-10-12T17:00:00.000Z, 1970-10-13T17:00:00.000Z, 1970-10-14T17:00:00.000Z, 1970-10-15T17:00:00.000Z, 1970-10-16T17:00:00.000Z, 1970-10-17T17:00:00.000Z, 1970-10-18T17:00:00.000Z, 1970-10-19T17:00:00.000Z, 1970-10-20T17:00:00.000Z, 1970-10-21T17:00:00.000Z, 1970-10-22T17:00:00.000Z, 1970-10-23T17:00:00.000Z, 1970-10-24T17:00:00.000Z, 1970-10-25T17:00:00.000Z]
java.lang.AssertionError: expected [12] but found [298]
Expected :12
Actual :298
Version 3.1.0
Quartz parser fails for day-of-week range of SUN-SAT. The Quartz definition appears correct but when the Quartz-based parser is created, the "DAY_OF_WEEK" constraints.stringMapping values are incorrect. MON = 1 even though mondayDoWValue = 2.
Use following test in CronParserQuartzIntegrationTest to reproduce:
@test
public void testSunToSat() {
// FAILS SUN-SAT: SUN = 7 and SAT = 6
parser.parse("0 0 12 ? * SUN-SAT");
}
Stack trace:
java.lang.IllegalArgumentException: Bad range defined! Defined range should satisfy from <= to, but was [%s, %s]
at com.cronutils.model.field.expression.Between.validate(Between.java:63)
at com.cronutils.model.field.expression.Between.(Between.java:39)
at com.cronutils.model.field.expression.Between.(Between.java:31)
at com.cronutils.parser.field.FieldParser.parseBetween(FieldParser.java:93)
at com.cronutils.parser.field.FieldParser.parse(FieldParser.java:69)
at com.cronutils.parser.field.CronParserField.parse(CronParserField.java:68)
at com.cronutils.parser.CronParser.parse(CronParser.java:96)
at com.cronutils.parser.CronParserQuartzIntegrationTest.testSunToSat(CronParserQuartzIntegrationTest.java:129)
Extract DateTimeFormatBuilder and related classes to another project, since is not cron functionality.
Import that project as Maven dependency, so that we can still use those classes for time formatting.
Using the samples on http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/crontrigger, the expression "0 10,44 14 ? 3 WED" fails validation using the isValid(...) method (for CronType.QUARTZ). The Cron-utils README indicates that the "?" is currently replaced with "*", and that renders the otherwise valid expression invalid. The same is true for "0 0 12 ? * SUN-SAT".
Hi,
the string constants are not working as expected. One can code "MON-FRI" for the day of the week, but "MON" for "just on mondays" doesn't work.
Same issue for the month. "JAN-FEB" is ok, but "JAN" for just january doesn't work, too.
Furthermore, some months doenst work with "from-to". With cron definition QUARTZ I've tried to pass "0 0 0 * JUL-AUG * *" - but this results in a
Exception in thread "main" java.lang.IllegalArgumentException: Values must not be empty
at org.apache.commons.lang3.Validate.notEmpty(Validate.java:300)
at com.cronutils.model.time.TimeNode.<init>(TimeNode.java:26)
at com.cronutils.model.time.ExecutionTimeBuilder.forMonthsMatching(ExecutionTimeBuilder.java:83)
at com.cronutils.model.time.ExecutionTime.forCron(ExecutionTime.java:83)
at mk.test.Main.testCronUtilsOwnDefinition(Main.java:42)
at mk.test.Main.main(Main.java:21)
My fault?
Thanks, Michael
Hi,
today I've played around with cron-utils but all my efforts to get it working as I expected failed....
I've tried to get a cron expression working that "executes" every monday at 18:00. My efforts to use a custom cron definition failed, so I tried the built-in CRON4J expression....
Here is what I've did:
// every monday at 18:00
final String cronExpression = "0 18 * * 1";
final CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.CRON4J);
final CronValidator validator = new CronValidator(cronDefinition);
System.out.println("isValid:" + validator.isValid(cronExpression));
final CronParser parser = new CronParser(cronDefinition);
final Cron cron = parser.parse(cronExpression);
final ExecutionTime executionTime = ExecutionTime.forCron(cron);
final CronDescriptor descriptor = CronDescriptor.instance(Locale.UK);
System.out.println(descriptor.describe(cron));
final DateTime now = DateTime.now();
final DateTime nextExec = executionTime.nextExecution(now);
final DateTime overNextExec = executionTime.nextExecution(nextExec);
System.out.println("now is: " + now);
System.out.println("next exec time: " + nextExec);
System.out.println("over next exec time: " + overNextExec);
This results in
isValid:true
at 18:00 at Monday day
now is: 2015-07-01T17:02:07.556+02:00
next exec time: 2015-07-01T18:00:00.000+02:00
over next exec time: 2015-07-01T18:00:00.000+02:00
As you can see, the date is always the 1st of july, whis is in fact no monday. I also don't understand why the "overnext time" is the same as the "next time".
Anything I did wrong?
Thank you, Michael
@dzsessona @bertleunis @AbhayParab Since you worked on cron-parser, you are welcome to contribute at cron-utils project.
"0 0 2/4 * * ?" is parsed like "every hour".
If you write a cron expression that contains a month or day of week, nextExection() ignores it.
Example where it's supposed to fire at 11:11 on November 11th:
CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
CronParser cronParser = new CronParser(cronDefinition);
ExecutionTime executionTime = ExecutionTime.forCron(cronParser.parse("0 11 11 11 11 ?"));
CronDescriptor descriptor = CronDescriptor.instance(Locale.UK);
System.out.println(descriptor.describe(cronParser.parse("0 11 11 11 11 ?")));
DateTime now = DateTime.now();
DateTime whenToExecuteNext = executionTime.nextExecution(now);
System.out.println(whenToExecuteNext.toString("yyyy/MM/dd HH:mm:ss", Locale.ENGLISH));
output is
at 11:11 at 11 day at November month
2015/03/02 11:11:00
So it (sort of) got the descriptor right, but the nextExecution() is actually in the past.
Hello, is it a known issue that the descriptor is throwing weird formatting and array exceptions?
This is my code:
try{
String cronExpr = "% HERE CRON EXPRESSION %";
CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.CRON4J);
CronParser parser = new CronParser(cronDefinition);
CronDescriptor descriptor = CronDescriptor.instance(Locale.UK);
descriptor.describe(parser.parse(cronExpr)
}catch(Exception e){
e.printStackTrace();
}
When I use:
*** 1,2,3,4,5,6 * 1,2,3 ***
I get:
java.lang.ArrayIndexOutOfBoundsException: 1
When I use:
* 1 1,2 * 4
I get:
java.util.UnknownFormatConversionException: Conversion = 'p'
Both examples return TRUE while validation.
More info:
CronType.CRON4J and CronType.UNIX has the same bug.
CronUtils 3.0 and 2.0 has the same bug.
I have htime-1.0, joda-time-2.4, guava-18.0, commons-lang3-3.4 in the classpath.
Could somebody try to replicate the issue?
Hello @KathyApplebaum
We saw your interest on cron-parser library. Perhaps cron-utils may also be useful to you.
Regards,
Add support for Romanian similar to @beradrian contribution.
I just started using the library, but the first test I ran seems to fail. I'm trying to specify minute, hour of day, and day of week. It looks like late in month has trouble. Using version 3.1.2. If I get some time I'll try to dig, but it'll be a bit before that happens.
See the following.
public class ScheduleHelperTest
{
DateFormat dfSimple = new SimpleDateFormat("hh:mm:ss MM/dd/yyyy a");
DateFormat df = new SimpleDateFormat("hh:mm:ss EEE, MMM dd yyyy a");
@Test
public void testBasicCron() throws ParseException
{
printDate("3:15:00 11/20/2015 PM");
printDate("3:15:00 11/27/2015 PM");
// printDate("3:15:00 11/29/2015 PM");
// printDate("3:15:00 11/30/2015 PM");
// printDate("3:15:00 12/01/2015 PM");
// printDate("3:15:00 12/02/2015 PM");
// printDate("3:15:00 12/29/2015 PM");
// printDate("3:15:00 12/30/2015 PM");
// printDate("3:15:00 12/31/2015 PM");
}
private void printDate(String startDate) throws ParseException
{
Date now = dfSimple.parse(startDate);
System.out.println("Starting: "+ df.format(now));
printNextDate(now, "0 6 * * 0");//Sunday
printNextDate(now, "0 6 * * 1");
printNextDate(now, "0 6 * * 2");
printNextDate(now, "0 6 * * 3");
printNextDate(now, "0 6 * * 4");
printNextDate(now, "0 6 * * 5");
printNextDate(now, "0 6 * * 6");
}
private void printNextDate(Date now, String cronString)
{
Date date = nextSchedule(cronString, now);
System.out.println("Next time: " + df.format(date));
}
public static Date nextSchedule(String cronString, Date lastExecution)
{
DateTime now = new DateTime(lastExecution);
CronParser cronParser =new CronParser(
CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX));
Cron cron = cronParser.parse(cronString);
ExecutionTime executionTime = ExecutionTime.forCron(cron);
DateTime nextExecution = executionTime.nextExecution(now);
return nextExecution.toDate();
}
}
Starting: 03:15:00 Fri, Nov 20 2015 PM
Next time: 06:00:00 Sun, Nov 22 2015 AM
Next time: 06:00:00 Mon, Nov 23 2015 AM <-- As expected, one day later
Next time: 06:00:00 Tue, Nov 24 2015 AM
Next time: 06:00:00 Wed, Nov 25 2015 AM
Next time: 06:00:00 Thu, Nov 26 2015 AM
Next time: 06:00:00 Fri, Nov 27 2015 AM
Next time: 06:00:00 Sat, Nov 21 2015 AM
Starting: 03:15:00 Fri, Nov 27 2015 PM
Next time: 06:00:00 Sun, Nov 29 2015 AM
Next time: 06:00:00 Mon, Dec 07 2015 AM <-- Jumps an extra week
Next time: 06:00:00 Tue, Dec 08 2015 AM
Next time: 06:00:00 Wed, Dec 02 2015 AM
Next time: 06:00:00 Thu, Dec 03 2015 AM
Next time: 06:00:00 Fri, Dec 04 2015 AM
Next time: 06:00:00 Sat, Nov 28 2015 AM
Description: Currently expressions with an offset from the last day of the month are not supported. The feature is described at Quartz tutorial.
Example:
CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
parser.parse("* * * L-3 * ?");
Output: java.lang.IllegalArgumentException: java.lang.NumberFormatException: For input string: "L"
Expected behaviour: Properly parse the expression, without throwing an exception.
First of all thanks for sharing this project!
"Expressions size do not match registered options!" is not really helpful, wrong spelling and somewhat a technical detail.
This should be something like: "Cron expression contains x parts but we expect one of [6,7]"
When enumerating candidates for ExecutionTime, year value should be contextual to requested reference date.
Why is ExecutionTime
(the class) not exposed as a publicly accessible class?
It would be very handy to get access to it instead of copy+pasting the class into application code.
Parsing can throw different kinds of exceptions. It would be nice if it would always throw IllegalArgumentException
eg:
parsing * *[triple space here]* * ?
throws a NumberFormatException with message For input string: ""
java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:592)
at java.lang.Integer.parseInt(Integer.java:615)
at com.cronutils.model.field.constraint.FieldConstraints.stringToInt(FieldConstraints.java:70)
at com.cronutils.model.field.On.<init>(On.java:28)
at com.cronutils.parser.field.FieldParser.parse(FieldParser.java:46)
at com.cronutils.parser.field.CronParserField.parse(CronParserField.java:68)
at com.cronutils.parser.CronParser.parse(CronParser.java:86)
Here's a new unit test for ExecutionTimeIntegrationTest. The println is just for debugging.
@Test
public void testHourlyIntervalTimeFromLastExecution() throws Exception {
DateTime now = DateTime.now();
int hour = now.getHourOfDay();
int previousHour = (hour > 0) ? (hour - 1) : 23;
String quartzCronExpression = "0 0 " + previousHour + " * * ?";
ExecutionTime executionTime = ExecutionTime.forCron(quartzCronParser.parse(quartzCronExpression));
System.out.println(executionTime.lastExecution(now));
assertTrue(executionTime.timeFromLastExecution(now).getStandardMinutes() <= 120);
}
for everything other than a dayOfWeek value == 1, nextExecution and lastExecution do not return correct results. Example below should return a date of 9/23 while it returns 9/30. Similiarly other days return a week further then they should. Only 1 gives the correct value of 9/21. I tried with previous versions of this and although i get a different result, it is still wrong. with previous versions i always get the next day (9/19)
CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX);
CronParser parser = new CronParser(cronDefinition);
Cron myCron = parser.parse("0 3 * * 3");
DateTime now = DateTime.now();
ExecutionTime executionTime = ExecutionTime.forCron(myCron);
DateTime nextExecution = executionTime.nextExecution(now);
The following fails as invalid cron expression:
CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 0 3 ? * SAT"));
Throws java.lang.IllegalArgumentException: Invalid value. Expected some integer, found SAT
The expression was actually taken from working quartz 2.2.1 based system.
Hi,
I have the following in my unix crontab :
00 21 * * * /appli/run.sh
When I executed
ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(cron));
I have the following error
Class java.lang.IllegalArgumentException Message Invalid chars in expression! Expression: APPLI Invalid chars: APPLI
Does I miss somehting ?
Here is the complete source code :
CronDefinition cronDefinition =
CronDefinitionBuilder.defineCron()
.withSeconds().and()
.withMinutes().and()
.withHours().and()
.withDayOfMonth()
.supportsHash().supportsL().supportsW().and()
.withMonth().and()
.withDayOfWeek()
.withIntMapping(7, 0) //we support non-standard non-zero-based numbers!
.supportsHash().supportsL().supportsW().and()
.withYear().and()
.lastFieldOptional()
.instance();
//or get a predefined instance
cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(com.cronutils.model.CronType.QUARTZ);
//create a parser based on provided definition
CronParser parser = new CronParser(cronDefinition);
DateTime now = DateTime.now();
ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(cron));
DateTime nextExecution = executionTime.nextExecution(now);
The following test case fails:
DateTime now = DateTime.now();
CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 0 3 ? * 6"));
DateTime last = executionTime.lastExecution(now);
DateTime next = executionTime.nextExecution(now);
Assert.assertNotEquals(last, next);
I expected the last to be "3 AM of the nearest Saturday looking past from now" and next to be "3 AM of the nearest Saturday looking forward". Am I wrong with my expectations?
Current implementation was developed using joda-time, since provides great date and time utils.
A new date, time and calendar API was released at Java 8. Since we want to keep compatibility with previous JDK versions, we want to maintain a branch with joda-time dependency, and another to leverage the new Java 8 API.
Hi
When I try t use the Quartz Parser for below expression, I got error
expression:
0 0/10 22 L * ?
Error message
Exception in thread "main" java.lang.IllegalArgumentException: Number 0 out of range [1,31]
at com.cronutils.model.field.constraint.FieldConstraints.validateInRange(FieldConstraints.java:111)
at com.cronutils.model.field.expression.FieldExpression.validate(FieldExpression.java:48)
at com.cronutils.model.field.expression.On.<init>(On.java:52)
at com.cronutils.parser.field.FieldParser.parseOn(FieldParser.java:136)
at com.cronutils.parser.field.FieldParser.parse(FieldParser.java:51)
at com.cronutils.parser.field.CronParserField.parse(CronParserField.java:68)
at com.cronutils.parser.CronParser.parse(CronParser.java:88)
I believe the issue is FieldParser/parseOn method. It set 0 for this fileds IntegerFieldValue on On class and it raises exception because DAY_OF_MONTH should be between 1-31
if (exp.contains("L")) {
specialChar = new SpecialCharFieldValue(SpecialChar.L);
exp = exp.replace("L", "");
if ("".equals(exp)) {
expression = "0";//to avoid a NumberFormatException
} else {
expression = exp;
}
}
Add feature to verify if DateTime matches a crontab.
Firstly very nice tool! thank you!
Now the problem:
@Override
void schedule(AppJobManager manager, _Job job) {
DateTime now = DateTime.now();
ExecutionTime executionTime = ExecutionTime.forCron(cron);
Duration nextExecution = executionTime.timeToNextExecution(now);
long seconds = nextExecution.getStandardSeconds();
manager.executor().schedule(job, seconds, TimeUnit.SECONDS);
}
Problem is I found it always returns 0
for the next time. Thus the job is executed huge number of times (>300) while I expected it to be executed for 1 time. The schedule method is called after the time is due and job is executed.
Setup a continuous delivery pipeline for SNAPSHOT artifacts to ensure they are published to Maven central with latest fixes and features being pushed to the github repository. This way, anyone depending on the latest version, would benefit from them as soon as changes are pushed.
Hello there, I am using the jar file from maven central cron-utils-1.1.2.jar
this is my code following the examples :
package com.mh.cronParser;
import com.cronutils.descriptor.CronDescriptor;
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.parser.CronParser;
import com.cronutils.validator.CronValidator;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
CronDefinition cronDefinition =
CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
//create a parser based on provided definition
CronParser parser = new CronParser(cronDefinition);
Cron quartzCron = parser.parse("0 23 ? * * 1-5 *");
System.out.println(quartzCron.asString());
//create a descriptor for a specific Locale
CronDescriptor descriptor = CronDescriptor.instance(Locale.UK);
//parse some expression and ask descriptor for description
String description = descriptor.describe(parser.parse("*/45 * * * * *"));
//description will be: "every 45 seconds"
//Validate if a string expression matches a cron definition:
CronValidator quartzValidator = new CronValidator(cronDefinition);
//getting a boolean result:
quartzValidator.isValid("0 23 ? * * MON-FRI *");
//or returning same string if valid and raising an exception if invalid
quartzValidator.validate("0 23 ? * * MON-FRI *");
}
}
and I got this exception when I tried to run the program
Exception in thread "main" java.lang.NoClassDefFoundError: com/google/common/collect/Maps
at com.cronutils.model.definition.CronDefinitionBuilder.<init>(CronDefinitionBuilder.java:39)
at com.cronutils.model.definition.CronDefinitionBuilder.defineCron(CronDefinitionBuilder.java:48)
at com.cronutils.model.definition.CronDefinitionBuilder.quartz(CronDefinitionBuilder.java:152)
at com.cronutils.model.definition.CronDefinitionBuilder.instanceDefinitionFor(CronDefinitionBuilder.java:188)
at com.mh.cronParser.Main.main(Main.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: java.lang.ClassNotFoundException: com.google.common.collect.Maps
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
... 10 more
looks like the built jar is not fine
For cron expressions which specify a day of the week to run on, ExecutionTime.lastExecution can return a date in the future if the last execution was in the previous month.
E.g. for cron expression "0 11 * * 1" if you try to get the last execution as of "2015-11-02T00:10:00" it will return "2015-11-16T11:00:00" rather than "2015-10-26T11:00:00" as expected.
This appear to be due to a bug in TimeNode.java which doesn't return the correct shift value when getting the nearest backward value.
It looks like a similar bug was fixed in TimeNode.getNearestForwardValue as part of issue #37
When using UNIX cron type (other not tested), the cron parser produces incorrect values for some step values (the one with slashes), e.g.:
Input | Parser output | Comment |
---|---|---|
0 0/1 * * * |
0 * * * |
The hour field is missing/empty. |
0 1/2 * * * |
0 /2 * * * |
The hour field should remain 1/2. |
0/1 * * * * |
* * * * |
The minute field is missing/emtpy. |
1/2 * * * * |
/2 * * * * |
The minute field should remain 1/2. |
Test used with cron-utils:3.1.2:
public class StepValuesTest {
private CronParser cronParser;
@Before
public void setup() {
CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX);
cronParser = new CronParser(cronDefinition);
}
@Test
public void everyEvenHourShouldBeParsedCorrectly() {
Cron cron = cronParser.parse("0 0/1 * * *");
assertThat(cron.asString(), anyOf(is("0 0/1 * * *"), is("0 /1 * * *"), is("0 * * * *")));
}
@Test
public void everyOddHourShouldBeParsedCorrectly() {
Cron cron = cronParser.parse("0 1/2 * * *");
assertThat(cron.asString(), is("0 1/2 * * *"));
}
@Test
public void everyEvenMinuteShouldBeParsedCorrectly() {
Cron cron = cronParser.parse("0/1 * * * *");
assertThat(cron.asString(), anyOf(is("0/1 * * * *"), is("/1 * * * *"), is("* * * * *")));
}
@Test
public void everyOddMinuteShouldBeParsedCorrectly() {
Cron cron = cronParser.parse("1/2 * * * *");
assertThat(cron.asString(), is("1/2 * * * *"));
}
}
Hi,
today I've played around with cron-utils but all my efforts to get it working as I expected failed....
I've tried to create a custom expression that contains just fields for "minute", "hour" and "dayOfWeek", so I can configure expressions like "every saturday and sunday at 18:00". But all I've got is a NPE. Her is what I've done:
final CronDefinition cronDefinition =
CronDefinitionBuilder.defineCron()
.withMinutes().and()
.withHours().and()
.withDayOfWeek().and()
.instance();
// every monday at 18:00
final String cronExpression = "0 18 1";
final CronValidator validator = new CronValidator(cronDefinition);
System.out.println("isValid:" + validator.isValid(cronExpression));
final CronParser parser = new CronParser(cronDefinition);
final Cron cron = parser.parse(cronExpression);
final ExecutionTime executionTime = ExecutionTime.forCron(cron);
The last line throws an NPE:
Exception in thread "main" java.lang.NullPointerException
at com.cronutils.model.time.ExecutionTimeBuilder.validate(ExecutionTimeBuilder.java:114)
at com.cronutils.model.time.ExecutionTimeBuilder.forDaysOfMonthMatching(ExecutionTimeBuilder.java:100)
at com.cronutils.model.time.ExecutionTime.forCron(ExecutionTime.java:81)
at mk.test.Main.testCronUtilsOwnDefinition(Main.java:49)
at mk.test.Main.main(Main.java:21)
Is it a bug or did I make a mistake?
Thank you, Michael
Add a module with Spring time formatter.
Sample cron expression
0 0/10 22 * * *
I run the core at 15:27, and it gives me the next execution time of 22:30, which should be 22:00. I believe it first look to the minute than hours, so next close value in range to 27 is 30.
İt should look first to year, month, etc, starting from bigger to smaller time unit.
For cron expressions where multiple days of the week are defined, the lastExecution can be wrong. For example the expression "* * * * 1,2" which should run every minute on Mondays and Tuesdays will actually be treated as running every minute on the 1st and 2nd of the month.
This appears to be due to FieldValueGeneratorFactory not handling "And" expressions correctly for Day of Week. On/Between expressions are handled by specific OnDayOfWeekValueGenerator and BetweenDayOfWeekValueGenerate, but And expressions are handled by the AndFieldValueGenerator.
Unix syntax * * * * 3,5-6 becomes 0 * * * * 3,5-6 * when using a CronType.UNIX to CronType.QUARTZ mapper
The result should be 0 * * * * 4,6-7 * as Monday is shifted in Quartz syntax
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.