Cron Expression Cheat Sheet
Cron syntax looks cryptic until you've memorized it, then you forget it again the moment you switch jobs. This is the reference: every field, both major dialects, and the mistakes that pass validation but run at the wrong time.
reference guide Hangfire Quartz.NET
// the two dialects
field order
Standard / Hangfire (5 fields)minute hour day-of-month month day-of-week
Quartz.NET (6 fields)second minute hour day-of-month month day-of-week
// special characters
syntax
*every value in this field,a list — MON,WED,FRI-a range — 9-17 means 9 through 17/a step — */15 means every 15 units, starting at 0?"no specific value" — Quartz.NET only, used on whichever of day-of-month/day-of-week you're not constrainingL"last" — Quartz.NET only; last day of the month, or last given weekday#"nth weekday of the month" — Quartz.NET only; 6#3 = third Friday// common schedules, both dialects
examples
Every minute
* * * * * / 0 * * * * ?Every 15 minutes
*/15 * * * * / 0 */15 * * * ?Every hour, on the hour
0 * * * * / 0 0 * * * ?Daily at 2:30 AM
30 2 * * * / 0 30 2 * * ?Every weekday at 9 AM
0 9 * * 1-5 / 0 0 9 ? * 2-6Every Monday at 6 AM
0 6 * * 1 / 0 0 6 ? * 2First day of every month, midnight
0 0 1 * * / 0 0 0 1 * ?Every 6 hours
0 */6 * * * / 0 0 */6 * * ?// mistakes that pass validation but run wrong
Setting both day-of-month and day-of-week to specific values doesn't mean "AND" — in standard cron it means "OR" (either condition triggers it), which almost never matches what you intended. If you want a specific weekday, leave day-of-month as
*.Day-of-week numbering differs by dialect: standard cron is 0–6 with 0 = Sunday. Quartz.NET is 1–7 with 1 = Sunday. The same digit means a different day depending which dialect you're reading — always check which one you're in before trusting a number.
Cron expressions run in whatever timezone the scheduler process is configured for — not necessarily UTC, and not necessarily the server's local time if the app sets one explicitly. A schedule that looks right can drift by hours after a timezone or daylight-saving change if this isn't pinned down.
A step value like
*/5 always starts counting from the field's zero point, not from "5 units from now." */5 on minutes fires at :00, :05, :10 — never at :02, :07, :12, no matter what minute you deployed at.// try it yourself
Build a schedule field-by-field, or paste an existing expression to get a plain-English explanation and its next five run times, with the Cron Builder & Explainer.
Almost every scheduler you'll meet uses one of two cron dialects. Standard cron (what Hangfire, Linux
crontab, and most CI systems use) has 5 fields: minute, hour, day-of-month, month, day-of-week. Quartz.NET adds a leading seconds field and uses?instead of*in whichever of day-of-month/day-of-week isn't in use — 6 fields total (a 7th, optional year field also exists but is rarely set).