Cron Expression Tutorial: Covering Linux, Spring and Quartz Scheduled Tasks

What's a cron expression? If you're reading this, you probably already know what it's for: when setting up scheduled tasks on Linux, Spring or Quartz, you write a cron expression to define the execution cycle. Cron is pronounced /krɒn/ — like 'chron' in chronology.

What’s a cron expression? If you’re reading this, you probably already know what it’s for: when setting up scheduled tasks on Linux, Spring or Quartz, you write a cron expression to define the execution cycle. Cron is pronounced /krɒn/ — like “chron” in chronology.

Cron types

A cron expression is a string of five to seven space-separated fields — and Linux, Spring and Quartz differ, so we’ll discuss them separately. First, the general symbols valid everywhere. To test your own expressions, I also have an online cron tester.

Each space-separated field can use digits and the symbols , - * / ? L W #, with these meanings:

  • Digits: a specific point in time
  • ,: enumerates values — essentially “or”. 1,3 means 1 or 3
  • -: a range. 1-3 means 1 through 3
  • *: matches any value in the field — any number
  • /: increments — essentially an interval. In the minutes field, 0/5 means starting at 0, every 5 minutes
  • ?: only allowed in the Day of Month and Day of Week fields; also means “any”. For example, to trigger on the 20th of each month regardless of weekday, you’d write 13 13 15 20 * ? — the last field must be ?, not *; using * would trigger on every weekday
  • L: “last”; only in Day of Week and Day of Month fields. 5L in Day of Week means the last Thursday
  • W: weekday (Mon–Fri); only in Day of Month. 5W: if the 5th is a Saturday, it triggers on the nearest weekday, Friday the 4th; if the 5th is a Sunday, it triggers on Monday the 6th; if the 5th is Monday–Friday, it triggers on the 5th
  • #: the nth weekday of the month; only in Day of Week. 4#2 means the second Wednesday of the month

Since the field layout differs per system, let’s go through them one by one.

Linux (crontab)

Linux uses 5 fields: Minutes, Hours, Day of Month, Month, Day of Week.

Using the notation above, let’s build one: “at minutes 0 and 30, from 18:00 to 23:00”. That’s 0,30 18-23 * * * — 0,30 means minute 0 or 30; 18-23 means hours 18 to 23; the asterisks match anything.

Java (Spring)

Spring’s @Scheduled gives us scheduled tasks with 6 fields: Second, Minutes, Hours, Day of Month, Month, Day of Week.

Same as Linux, but with a seconds field added — precision down to the second. Let’s build one: “at 18:00 sharp on the 28th through 31st of each month”. That’s 0 0 18 28-31 * ? — the first 0 is 0 seconds, the second 0 is 0 minutes, 18 is 18:00, 28-31 is the 28th through 31st, the asterisk is any month, the question mark is any weekday.

Quartz

In the Quartz scheduler, a cron expression adds one more field on top of Spring’s — 7 fields: Second, Minutes, Hours, Day of Month, Month, Day of Week, Year (optional).

Quartz is the more professional scheduling framework, hence the year field. It’s optional — you can omit it entirely, and we usually do — but if you need to trigger in a specific year, it’s there.

Let’s practice one more: “at 18:00 sharp on the last day of every month” — a common one, month-end. That’s 0 0 18 L * ? — 0 seconds, 0 minutes, 18:00, L in the Day of Month field means the last day, the asterisk is any month, the question mark is any weekday.

Wrap-up

Once you understand what each field means, it’s easy — honestly much easier to learn than regex. Go play with the online cron tester and explore.