Nimble Toolbox

Cron expression explainer

Type or paste a crontab line, a GitHub Actions or Kubernetes schedule, a Quartz or Spring expression, or an AWS cron() rule, and it is explained as you type: what it means in plain English, what each field matches, and the next five times it runs. If it will not parse, the message names the field at fault.

How to use it#

  1. Type or paste a cron expression into the box above, such as 30 9 * * 1-5.
  2. Read the sentence, and check each field below it for the values it matches.
  3. Choose UTC or your time zone to match where the server runs, and check the next five runs.
  4. Copy the sentence if you want it for a comment beside the crontab line.

The five fields, in order#

A cron expression is five fields separated by spaces: minute, hour, day of the month, month, and day of the week. 30 9 * * 1-5 reads as minute 30, hour 9, any day of the month, any month, Monday to Friday, which is 09:30 on weekdays. A star means every value the field can hold.

Each field takes a single value, a list such as 1,15, a range such as 9-17, or a step such as */15, which is every 15th value from the start of the field. Steps work on ranges too: 9-17/2 is 9, 11, 13, 15, and 17. Months and weekdays can be written as their first three letters, JAN to DEC and SUN to SAT, and Sunday is both 0 and 7.

GitHub Actions workflows and Kubernetes CronJobs use these same five fields, so a schedule copied from either reads here as it is. Anything the parser cannot read is named by field and value, which makes the page a quick cron validator before a line goes into a config file.

Six or seven fields: Quartz, Spring, and AWS#

Quartz and Spring, including the @Scheduled cron in a Spring Boot app, put a seconds field in front, making six, and Quartz allows a year on the end as a seventh. AWS EventBridge also uses six, but keeps the minute first and adds the year on the end instead. Quartz and AWS count weekdays from 1 for Sunday, so MON-FRI there is 2-6, while Spring counts from 0 like standard cron. Writing the days as names, MON-FRI, reads the same in all of them.

The layouts are told apart by where the ? sits. Quartz and AWS both require one in a day field, which Quartz has fourth or sixth and AWS third or fifth. Six seconds-first fields with no ? are read as Spring. A year such as 2027 in the last of six fields, or the cron() wrapper AWS writes around the expression, marks it as AWS, and seven fields are always Quartz. The page says which layout it read in a row of its own, because the same 2 is Monday in one and Tuesday in another.

An AWS rate() expression is an interval rather than a calendar schedule, so there is nothing to explain.

L, W, and #: last days and nth weekdays#

Quartz, Spring, and AWS read three extra characters in the day fields. In the day of the month, L is the last day, L-3 the third day before it, LW the last Monday to Friday, and 15W the weekday nearest the 15th. In the day of the week, FRIL or 6L is the last Friday of the month and MON#2 the second Monday. L on its own in the day of the week is Saturday.

The nearest weekday never crosses into another month. When the 1st is a Saturday, 1W runs on Monday the 3rd rather than on the Friday before, and when the 31st is a Sunday, 31W runs on Friday the 29th. The next runs list shows exactly which dates each one lands on. Standard crontab has none of this, so a five-field line using them is refused with a note on where they belong. To write one of these without remembering the syntax, use the cron expression generator.

The day rule that catches people out#

0 0 1 * 1 looks like midnight on the 1st of the month if it is a Monday. It is not. When both day fields are restricted, cron runs on a day that matches either of them, so that line fires on the 1st of every month and also on every Monday.

The rule depends on how the fields are written, not on what they match. If either day field starts with a star, both have to match. That makes */2 in the day of the month a different thing from 1-31/2, even though both match the same days. The explanation says or when the either-day rule is in force, and flags it in a row of its own.

Time zones, and why the next runs matter#

Cron reads the schedule in the time zone of the machine it runs on. Most servers, containers, and cloud schedulers run in UTC, so 0 9 * * * on a server is 09:00 UTC, which is a different moment in most of the world. The next runs are shown in UTC by default with your own clock time beside each one, or in your time zone if that is where the job runs.

The list of next runs is the fastest way to catch a mistake. A job meant for the first Monday of the month, a schedule that skips February, or a step that does not divide the hour evenly all look reasonable written down and wrong in the list. */7 in the minute field, for example, runs at 56 and then again at 0, four minutes later.

Frequently asked questions#

Why does it run on days I did not ask for?

#

Because both day fields are restricted. With a value in the day of the month and another in the day of the week, cron runs on any day that matches either one, not only on days that match both. 0 0 13 * 5 runs on the 13th of every month and on every Friday, rather than just on Friday the 13th. To need both, the job has to check the date itself.

Which time zone does cron use?

#

The time zone of the machine running it, unless the crontab sets CRON_TZ or TZ, or the scheduler has a time zone setting of its own. GitHub Actions reads schedules in UTC, as do EventBridge rules on AWS, and a Kubernetes CronJob follows the timeZone in its spec when it has one. Choose UTC or your time zone beside the expression to match, and the next runs are worked out in that zone.

What happens when the clocks change?

#

In a zone with daylight saving, a time inside the hour the clocks skip does not happen that day, and this page leaves it out of the next runs. Cron implementations differ here: some run a skipped job as soon as the clocks change and some run a repeated hour twice. Running jobs in UTC avoids the question.

How are six-field expressions read?

#

As AWS EventBridge when the third or fifth field holds the ? that AWS requires, when the last field is a year, or when the expression is wrapped in cron(). As Quartz, seconds first with Sunday as 1, when the fourth or sixth field holds a ?, and always when there are seven fields, the seventh being a year. Otherwise the first field is seconds and Sunday is 0 or 7, the way Spring counts it. The Read as row says which applied. Standard crontab has no sixth field, so a six-field line will not work in a Linux crontab.

What do @daily and the other shortcuts mean?

#

@hourly is 0 * * * *, @daily and @midnight are 0 0 * * *, @weekly is 0 0 * * 0, @monthly is 0 0 1 * *, and @yearly and @annually are 0 0 1 1 *. Type one in and it is explained like any other line. @reboot runs once when cron starts, so it has no schedule to show.