crontab.in
monitor with cron.watch
java scheduling

Scheduling in Java.

Spring and Quartz both use cron strings — but with an extra seconds field and different day-of-week numbering. Here is how to get it right.

Heads-up: Java cron ≠ Unix cron

Both Spring and Quartz use a 6-field cron expression that starts with seconds:

# Unix cron (5 fields)
min hour dom mon dow
0   9    *   *   1-5

# Spring / Quartz (6 fields — seconds first!)
sec min hour dom mon dow
0   0   9    *   *   MON-FRI

Spring @Scheduled

@Component
public class Jobs {

    // every weekday at 09:00 (sec min hour dom mon dow)
    @Scheduled(cron = "0 0 9 * * MON-FRI", zone = "UTC")
    public void report() {
        // ...
    }

    // every 15 minutes
    @Scheduled(cron = "0 */15 * * * *")
    public void poll() { }
}

Enable it with @EnableScheduling on a configuration class.

Quartz Scheduler

JobDetail job = JobBuilder.newJob(ReportJob.class).build();

Trigger trigger = TriggerBuilder.newTrigger()
    .withSchedule(CronScheduleBuilder
        .cronSchedule("0 0 9 ? * MON-FRI")   // note the ?
        .inTimeZone(TimeZone.getTimeZone("UTC")))
    .build();

scheduler.scheduleJob(job, trigger);

ScheduledExecutorService (fixed intervals)

For simple fixed-rate work with no cron semantics, the JDK has you covered:

ScheduledExecutorService ex = Executors.newScheduledThreadPool(1);
ex.scheduleAtFixedRate(this::poll, 0, 15, TimeUnit.MINUTES);

Monitor it free with cron.watch

A scheduled bean that throws on startup, or a JVM that crashes, takes its schedule down with it — quietly. A schedule is only a promisecron.watch tells you if the job actually ran, alerts you when it silently fails, skips, or runs long, and keeps a history of every run.

// after the job body, ping cron.watch
var client = HttpClient.newHttpClient();
client.send(
    HttpRequest.newBuilder(URI.create("https://cron.watch/s/your-id")).build(),
    HttpResponse.BodyHandlers.discarding());
Get cron.watch free ↗ Analyze your crontab →

More scheduling guides