Cron Expressions: Cheat Sheet and Common Pitfalls

A mistyped schedule either never fires or fires at three in the morning when nobody is watching. This guide packs field semantics, common expressions, and special characters into quick tables. It then walks through the traps that break cron jobs most often, each with a way to verify.

What the Five Fields Control

A standard cron expression has five fields separated by spaces: minute, hour, day of month, month, and day of week. The Cron Generator on this site parses exactly this format. Type an expression and it shows a plain-language description plus the next five run times, recalculated as you edit.

FieldRangeSyntax acceptedExample
Minute0-59Numbers, lists, ranges, steps0,30.
Hour0-23Same, and ranges may wrap past midnight*/6.
Day of month1-31A question mark may replace the star1,15.
Month1-12Numbers or jan through dec1,4,7,10.
Day of week0-70 and 7 both mean Sunday, or sun through sat1-5.

Three details worth memorizing. Input is case-insensitive, so MON and mon both parse. A 7 in the weekday field maps to Sunday, which is the same target as 0. The question mark is valid only in the day-of-month and day-of-week fields, and anywhere else it raises an error. The field count must be exactly five, though runs of spaces are collapsed.

The name abbreviations come from the first three letters of English month and weekday names. jan is January, dec is December, and sat is Saturday. Plain numbers are the safest choice. Abbreviations help when you paste an expression from a blog post and want to check it against the parser.

A useful mental model treats the fields as filters in layers. The month removes most days first. Day of month and day of week then remove nearly all the rest. Minute and hour finally pick the moment inside the surviving day. Reasoning in that order keeps complex expressions from tangling.

Common Expressions at a Glance

The fourteen rows below cover most daily needs. The first six match the preset buttons in the generator, so you can click one and watch the description plus the run preview.

ExpressionMeaning
* * * * *Every minute.
7 * * * *At minute 7 of every hour.
0 * * * *On the hour, every hour.
30 8 * * *Every day at 08:30.
0 9 * * 1-5Weekdays at 09:00.
0 10 * * 6Saturdays at 10:00.
30 8,20 * * *Every day at 08:30 and 20:30.
0 */6 * * *Every 6 hours, landing on 0, 6, 12, and 18.
*/15 * * * *Every 15 minutes.
0 9 1 * *On the 1st of every month at 09:00.
0 9 1,15 * *On the 1st and 15th at 09:00.
0 9 1 1,4,7,10 *First day of each quarter-opening month at 09:00.
0 9 1 1 *Once a year on January 1st at 09:00.
0 22-2 * * *On the hour from 22:00 to 02:00, using a wrapping range.

Pick the frequency ceiling before you write anything. Heartbeat jobs can run every minute. Reports fit hourly or daily slots. Billing belongs on a fixed monthly date. The higher the frequency, the lighter each run must be, because stacking heavy jobs will crush the machine. State the schedule in one plain sentence first, then translate it into five fields.

Quarterly jobs read clearest as 1,4,7,10. In this tool the month form 1/3 produces the same set, but number-plus-step is not accepted everywhere, so verify before carrying it to another system. Annual jobs should pin the month and the day explicitly rather than leaning on month-end syntax.

Verifying an Expression in the Tool

Tables give you a starting point, and the tool confirms it. The loop takes about two minutes.

  1. Paste the expression and read the English description. Check that the wording matches your intent.
  2. Look at the next five run times and verify the dates, weekdays, and times.
  3. If one field feels uncertain, use the quick buttons under that field or edit it alone, and the preview updates at once.
  4. Copy the confirmed expression from the output box. Never retype it by hand, because one wrong character ruins everything.

When both day fields are restricted, the tool shows a dedicated notice, and the preview dates reveal the OR behavior. The run preview uses your device's local clock. If the server runs in another zone, redo the mental conversion against the server clock before shipping.

Special Characters and Shorthands

Symbols decide which moments match. The table below explains each one and records whether the site tool accepts it.

SyntaxMeaningSite tool
*Matches every value in the field.Supported.
,List; the union of the values.Supported.
-Inclusive range; the hour field may wrap past midnight, as in 22-2.Supported.
/Step. Star plus step starts at the field minimum; number plus step starts at that number and runs to the maximum.Supported.
?Placeholder equal to the star, allowed only in the day fields.Supported.
NamesMonths accept jan through dec; weekdays accept sun through sat.Supported.
LThe last day of the month, or the last given weekday of the month.Not supported here; verify in the target environment.
WThe nearest weekday to the given day of month.Not supported here; verify in the target environment.
#The nth weekday of the month, as in 5#3.Not supported here; verify in the target environment.
@formsShorthands such as @daily, @weekly, @monthly, and @reboot.Not supported here; verify in the target environment.

The site tool accepts exactly five space-separated fields, so @daily is rejected as a field-count error. To say "daily at midnight", write 0 0 * * *. The L, W, and # symbols are extensions, and behavior differs across cronie, systemd timers, and cloud schedulers. Read the target system's documentation first, or run a trial in a test environment and compare the firing times against your intent.

Traps That Break Schedules

Two Day Fields Mean OR, Not AND

People read 0 0 1 * 1 as "the 1st, only on a Monday". The real semantics are "the 1st of the month, or every Monday". When day of month and day of week are both restricted, a match on either one fires the job. That is the standard rule. The generator flags this case with a notice, and the preview dates give it away, because far more than one day per month lights up. Restrict the day of month and leave the weekday as a star when dates matter. Restrict the weekday and leave the day as a star or a question mark when the week matters.

The Missing 31st

The expression 0 0 31 * * looks like "the last day of every month". It actually runs only in months that contain a 31st. February never qualifies, and April, June, September, and November have 30 days. The job sits silent for whole months without a single error message, which is what makes this trap expensive. The site tool does not support the L syntax, so "last day of the month" cannot be written directly. A common portable replacement is a daily job whose script checks whether tomorrow is the 1st and does the real work only then. That approach relies on no extension syntax and survives migration.

Time Zones: There Is No Zone Field

The five fields describe wall-clock time, never a zone. The same 0 9 * * * runs at nine local on a Beijing server. On a UTC server it runs at nine UTC, an eight-hour gap. Servers and cloud hosts commonly default to UTC. Run the date command on the target machine before filling in the fields. The generator computes run times on your device's local clock. That may differ from the server, so recheck the mapping when you migrate an expression between environments.

Containers add one more layer. The zone inside a container follows the image, and most images default to UTC unless a zone package is installed. Some implementations offer extensions like CRON_TZ or a zone suffix. Those are non-standard, so confirm support before depending on them. The sturdiest habit is writing down the server zone, the expression, and the expected fire times side by side.

Daylight Saving Shifts

Zones with daylight saving time misbehave twice a year. In spring, clocks jump forward, and some wall-clock times simply never occur that day, so jobs scheduled inside the gap are skipped. In autumn, clocks fall back, the same wall-clock time happens twice, and a schedule matched on wall time can fire twice. UTC has no daylight saving, so keeping servers on UTC sidesteps most of this. If local time is mandatory, watch the logs around each shift and count the runs.

Where Steps Start

A star plus a step starts from the field minimum. Minute */5 hits 0, 5, 10, up to 55, not aligned to the moment you deployed. Month */3 hits 1, 4, 7, and 10, which maps neatly onto the four quarter-opening months. A number plus a step starts at that number: hour 9/2 hits 9, 11, 13, up to 23. For "every 30 minutes starting on the hour", write 0/30 or 0,30, because 5/30 would begin at minute 5. Lists and steps mix: minute 0,10-30/10 hits 0, 10, 20, and 30. Check one day of run records after deployment and the starting point is confirmed.

Wrapping Ranges Are Not Universal

The hour range 22-2 matches 22, 23, 0, 1, and 2 in this tool, which suits overnight duty schedules. Many classic implementations only accept ranges that run upward, and they treat 22-2 as empty or reject it outright. Such differences rarely appear on page one of the manual. Before moving an expression to a new environment, replay it through the next-run preview there and only then go live.

Lines That Look Right but Fail

Each line below comes from a real support case, with the reason attached.

ExpressionProblem
60 0 * * *The minute exceeds 0-59, so parsing fails.
0 9 * * 8The weekday exceeds 0-7, so parsing fails.
0 0 31 2 *February has no 31st, so this never runs.
0 ? * * *The question mark sits in the hour field, where it is not allowed.
* * * *Only four fields; exactly five are required.
@hourlyThe tool rejects shorthands; expand it to 0 * * * *.

Three Moves Before You Ship

First, paste the expression into the generator and read the description until it matches your intent. Second, inspect the next five run times, paying attention to dates and weekdays, especially when both day fields are involved. Third, watch the logs for the first week in production and compare actual runs with the plan. Once all three pass, the expression has earned some trust. Record the final expression together with the server time zone, its meaning, and the verification date in your deployment notes. The person inheriting the system in six months should not have to reverse-engineer your intent.

Tools mentioned in this guide