Refine search
/**
* Gathers the next time that the cron expression will be valid
* @param cron
* @return the next valid date
public static Date getNextValidTime(String cron) {
Date nextValidTime = null;
try {
if (StringUtils.isNotBlank(cron)) {
nextValidTime = new CronExpression(cron).getNextValidTimeAfter(new Date());
} catch (ParseException e) {
LOG.warn("Unable to parse the given cron expression: " + cron, e);
return nextValidTime;
/**
* @return if the cronExpression is valid or not.
public static boolean isCronExpressionValid(final String cronExpression,
final DateTimeZone timezone) {
if (!CronExpression.isValidExpression(cronExpression)) {
return false;
* The below code is aimed at checking some cases that the above code can not identify,
* e.g. <0 0 3 ? * * 22> OR <0 0 3 ? * 8>. Under these cases, the below code is able to tell.
final CronExpression cronExecutionTime = parseCronExpression(cronExpression, timezone);
if (cronExecutionTime == null || cronExecutionTime.getNextValidTimeAfter(new Date()) == null) {
return false;
return true;
/**
* Create a <CODE>CronCalendar</CODE> with the given cron exprssion,
* <CODE>baseCalendar</CODE>, and <code>TimeZone</code>.
* @param baseCalendar the base calendar for this calendar instance –
* see {@link BaseCalendar} for more information on base
* calendar functionality
* @param expression a String representation of the desired cron expression
* @param timeZone
* Specifies for which time zone the <code>expression</code>
* should be interpreted, i.e. the expression 0 0 10 * * ?, is
* resolved to 10:00 am in this time zone. If
* <code>timeZone</code> is <code>null</code> then
* <code>TimeZone.getDefault()</code> will be used.
public CronCalendar(Calendar baseCalendar,
String expression, TimeZone timeZone) throws ParseException {
super(baseCalendar);
this.cronExpression = new CronExpression(expression);
this.cronExpression.setTimeZone(timeZone);
/**
* Constructs a new {@code CronExpression} as a copy of an existing
* instance.
* @param expression
* The existing cron expression to be copied
public CronExpression(CronExpression expression) {
* We don't call the other constructor here since we need to swallow the
* ParseException. We also elide some of the sanity checking as it is
* not logically trippable.
this.cronExpression = expression.getCronExpression();
try {
buildExpression(cronExpression);
} catch (ParseException ex) {
throw new AssertionError();
if (expression.getTimeZone() != null) {
setTimeZone((TimeZone) expression.getTimeZone().clone());
final RFC5545Schedule rfc5545Schedule = new RFC5545Schedule(request.getSchedule().get());
nextRunAtDate = rfc5545Schedule.getNextValidTime();
scheduleFrom = new Date(rfc5545Schedule.getStartDateTime().getMillis());
} else {
scheduleFrom = new Date(now);
final CronExpression cronExpression = new CronExpression(request.getQuartzScheduleSafe());
if (request.getScheduleTimeZone().isPresent()) {
cronExpression.setTimeZone(TimeZone.getTimeZone(request.getScheduleTimeZone().get()));
nextRunAtDate = cronExpression.getNextValidTimeAfter(scheduleFrom);
nextRunAt = Math.max(nextRunAtDate.getTime(), now); // don't create a schedule that is overdue as this is used to indicate that singularity is not fulfilling requests.
final CronExpression cronExpression;
try {
cronExpression = new CronExpression(cronSchedule);
} catch (final Exception pe) {
throw new IllegalStateException("Cannot schedule " + connectable + " to run because its scheduling period is not valid");
final Date initialDate = cronExpression.getTimeAfter(new Date());
final long initialDelay = initialDate.getTime() - System.currentTimeMillis();
CronExpression e = new CronExpression("0 00 10 ? * *");
Date nextValidTimeAfter = e.getNextValidTimeAfter(new Date());
FiniteDuration d = Duration.create(
nextValidTimeAfter.getTime() - System.currentTimeMillis(),
TimeUnit.MILLISECONDS);
public static Date getNextFireTime(CronExpression cron) {
return cron.getNextValidTimeAfter(new Date());
private long nextRunTime() {
To not increase the interval, we also have to adapt the
current time, by subtracting the randomOffset. Otherwise
the interval will be increased by the randomOffset.
return cronExpression.getNextValidTimeAfter(new Date(System.currentTimeMillis() - randomOffset)).getTime();
/** * 返回下一个执行时间根据给定的Cron表达式 * @param cronExpression Cron表达式 * @return Date 下次Cron表达式执行时间 public static Date getNextExecution(String cronExpression) { try { CronExpression cron = new CronExpression(cronExpression); return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis())); } catch (ParseException e) { throw new IllegalArgumentException(e.getMessage());
CronExpression cron = new CronExpression("0 15 10 ? * *"); Date today = new Date(); Date previousExecution = cron.getTimeBefore(today);
public void start() {
log.info("Starting scheduler [ " + cronExpression.getCronExpression() + " ]");
timer = vertx.setPeriodic(5000, timer -> redisClient.get("schedulers:" + name, reply -> {
final String stringValue = reply.result();
To guarantee that a scheduler is always triggered after the same interval,
we have to subtract the randomOffset from the current time. This way we don’t
change the behavior of the scheduler, because we simply “adjust” the current time.
if (stringValue == null || Long.parseLong(stringValue) <= (System.currentTimeMillis() - randomOffset)) {
// Either first use of the scheduler or run time reached.
// We need to set the next run time
final long nextRunTime = nextRunTime();
if (log.isTraceEnabled()) {
log.trace("Setting next run time to " + SimpleDateFormat.getDateTimeInstance().format(new Date(nextRunTime)));
redisClient.getset("schedulers:" + name, "" + nextRunTime, event -> {
String previousValue = event.result();
if (stringValue != null && stringValue.equals(previousValue)) {
// a run time was set and we were the first instance to update it
trigger();
if ((!executed && executeOnStartup) || executeOnReload) {
executed = true;
trigger();
final Date next = new CronExpression(schedule.getCron()).getNextValidTimeAfter(now);
writer.write(';');
writer.write(df.format(next));
writer.write(';');
writer.write(String.valueOf(next.getTime()));
} catch (final ParseException pe) {
log.error("Invalid CRON expression {} : {}", schedule.getCron(), pe.getMessage());
writer.write(";ERROR;ERROR");
public void validate(ValidationContext validationContext) {
if (timerSpec == null) {
errors.add(TIMER_SPEC, "Timer Spec can not be null.");
return;
try {
new CronExpression(timerSpec);
} catch (ParseException pe) {
errors.add(TIMER_SPEC, "Invalid cron syntax: " + pe.getMessage());
public static void validateCronExpression(String cronExpression) {
String quartzCron = getQuartzCronExpression(cronExpression);
try {
CronExpression.validateExpression(quartzCron);
} catch (ParseException e) {
throw new IllegalArgumentException(String.format("Invalid cron expression '%s': %s", cronExpression,
e.getMessage()), e);
private void validateTimer() { if (isBlank(schedule)) { return; try { new CronExpression(schedule); } catch (ParseException pe) { errors.add(SCHEDULE, "Invalid cron syntax for backup configuration at offset " + pe.getErrorOffset() + ": " + pe.getMessage());
@Managed public void setSchedule(String cronExpression) throws ParseException { if (!CronExpression.isValidExpression(cronExpression)) { throw new ParseException("not a valid cron expression : " + cronExpression, -1); set("schedule", cronExpression);
public static String timerToCronString(String timer) {
try {
CronExpression cronExpression = timerToCronExpression(timer);
return cronExpression.getCronExpression();
} catch (ParseException e) {
LOG.error("Unable to create CronExpression from timer {}. Error: {}", timer, e.getMessage(), e);
return null;
/**
* Cron 표현식의 유효성을 체크합니다
@RequestMapping(value = "/datasources/validation/cron", method = RequestMethod.POST)
public ResponseEntity<?> checkCronExpression(@RequestParam String expr,
@RequestParam(value = "timeZone", required = false, defaultValue = "UTC") String timeZone,
@RequestParam(value = "count", required = false, defaultValue = "5") int count) {
CronExpression cronExpression = null;
try {
cronExpression = new CronExpression(expr);
} catch (ParseException e) {
return ResponseEntity.ok(new CronValidationResponse(false, e.getMessage()));
DateTimeZone zone = DateTimeZone.forID(timeZone);
cronExpression.setTimeZone(zone.toTimeZone());
LOGGER.debug("Timezone summary : {}", cronExpression.getExpressionSummary());
List<String> afterTimes = Lists.newArrayList();
DateTime time = DateTime.now();
for (int i = 0; i < count; i++) {
time = new DateTime(cronExpression.getNextValidTimeAfter(time.toDate()));
afterTimes.add(time.withZone(zone).toString());
return ResponseEntity.ok(new CronValidationResponse(true, afterTimes));
public CronTrigger convert2QuartzTrigger(JobDetail jobDetail){
CronExpression ce = null;
try {
checkArgument(!Strings.isNullOrEmpty(cronExpression),"cronExpression参数非法");
ce= new CronExpression(this.cronExpression);
} catch (ParseException e) {
e.printStackTrace();
return TriggerBuilder.newTrigger()
.forJob(jobDetail)
.withSchedule(CronScheduleBuilder.cronSchedule(ce))
.withIdentity(this.name,this.group)
.withDescription(this.description)
.build();