Cron Expression Generator

What cron expression runs my job at the right time?

Turn a plain schedule into a cron expression you can paste directly into your crontab, CI config, or cloud scheduler. Set frequency, time, and day fields — the tool assembles the five-field expression and explains when it runs.

Updated July 2026 · How this works

Example calculation — edit any field to use your own numbers

Worth knowing
How It Works
The formula, explained simply

Every cron daemon is essentially a clock watcher. Once per minute it wakes up, reads the current time, and scans every entry in the crontab. For each entry it asks one question: do all Minute: 0 | Hour: 9 | Day of month: * | Month: * | Day of week: * fields match right now? If yes, it spawns the job. If no, it goes back to sleep. The whole system is stateless — it has no memory of when a job last ran, no concept of missed windows, and no backfill logic.

The five positional fields form a coordinate in time-space. Think of them as nested sieves. The month field filters down to one or more months per year. The day-of-month and day-of-week fields filter further to specific calendar dates. The hour and minute fields pin the exact moment within that day. A job only fires when the current timestamp passes through all five sieves at once. That AND logic is the entire engine.

Special characters extend what the position system can express. The asterisk (*) removes a sieve entirely, passing every value through. A slash (/) creates a step pattern — */5 passes 0, 5, 10, 15, and so on. Commas allow multiple discrete values ( 1,15,30 in the minute field fires three times per hour). Hyphens define contiguous ranges (1-5 in the day-of-week field means Monday through Friday). These four characters cover the vast majority of real scheduling needs without any programming logic.

When To Use This
Right tool, right situation

Use a cron expression when the job needs to fire on a clock-based schedule that repeats indefinitely: database backups, log rotation, cache warming, report generation, health checks, and similar periodic tasks. Cron is well-suited when the job is idempotent — running it twice accidentally causes no harm — because cron provides no duplicate-suppression and no missed-window recovery.

Cron is not the right tool when job timing depends on events rather than the clock. If a job should run after a user completes a purchase, after an upstream data pipeline finishes, or after a file arrives in a directory, an event-driven queue or workflow orchestrator handles the dependency relationship better than any time expression can. Similarly, for jobs that need sub-minute precision, standard five-field cron is insufficient — some extended implementations add a seconds field, but it is non-standard and not portable across daemons.

Also reconsider cron when the schedule needs to respect business-day logic (skip holidays, skip weekends dynamically based on a calendar) or when the job must not overlap with its own previous run. A cron daemon does not check whether the previous invocation finished before starting the next one. A job that occasionally runs longer than its interval will stack up concurrent processes. For overlap protection, use a wrapper that checks a lock file or a dedicated job scheduler that understands run duration.

Common Mistakes
Why results sometimes look wrong

Mistake: setting both day-of-month and day-of-week to non-wildcard values. Most POSIX cron implementations treat this combination as OR, not AND. A job with DOM= 15 and DOW=5 fires on the 15th of every month and also every Friday — potentially far more often than intended. The safe rule: pin one of the two day fields and leave the other as an asterisk. Only use both when you genuinely want the union of both conditions.

Mistake: assuming the server uses your local timezone. Cron daemons run in the timezone of the server process, not the user who wrote the expression. A daily job set to run at hour 9 fires at 9 AM server time, which may be 2 AM or 5 PM in the developer's local time depending on their location and whether the server is set to UTC. Always confirm the daemon timezone before deploying time-sensitive jobs — most production servers run UTC specifically to avoid this confusion.

Mistake: not accounting for months with fewer than 31 days. A monthly job with DOM=31 silently skips February, April, June, September, and November — those months never have a 31st day, so the cron condition is never satisfied. For reliably end-of-month execution, use application logic rather than a fixed DOM value, or accept that the job will run on the last day only in 31-day months.

The Math
Worked examples and deeper derivation

A cron expression is a five-tuple: M H DOM MON DOW. Each position has a defined integer range. The minute field (M) accepts integers from 0 through 59. The hour field (H) accepts 0 through 23 in 24-hour format. Day of month (DOM) accepts 1 through 31. Month (MON) accepts 1 through 12. Day of week (DOW) accepts 0 through 6, with 0 and 7 both representing Sunday in most implementations.

For the example schedule of daily at 09:00, the generator fills the fields as: minute = 0, hour = 9, day-of-month = wildcard, month = wildcard, day-of-week = wildcard. The resulting five-tuple is 0 9 * * *. The daemon evaluates this as: current_minute == 0 AND current_hour == 9 AND TRUE AND TRUE AND TRUE. The expression collapses to a single truth check on minute and hour, satisfied exactly once every 24-hour cycle.

For the weekly Friday case from the worked examples — 0 9 * * * using the weekly Friday inputs — the evaluation becomes: current_minute == 0 AND current_hour == 9 AND TRUE AND TRUE AND current_dow == 5. This is satisfied once per week. The field breakdown Minute: 0 | Hour: 9 | Day of month: * | Month: * | Day of week: * shows exactly which positions carry constraints and which pass everything through with an asterisk. Reading left-to-right across the five fields tells you the full firing rule in one glance once you know the positional order.

Daily database backup at 2:15 AM
Frequency: Daily, Minute: 15, Hour: 2
The generator produces 15 2 * * *. The cron daemon checks all Minute: 15 | Hour: 2 | Day of month: * | Month: * | Day of week: * simultaneously — every minute, it asks whether the current minute is 15 AND the current hour is 2 AND the day, month, and day-of-week are wildcards (always true). The job fires exactly once per day at 2:15 AM server time. Running backups in the early morning avoids peak traffic and leaves a full day to notice failures before the next business cycle begins.
Friday afternoon report generation at 9:00 AM
Frequency: Weekly, Minute: 0, Hour: 9, Day of week: Friday (5)
The generator produces 0 9 * * 5. The day-of-week field uses the value 5 for Friday in standard POSIX numbering (Sunday is 0). The AND logic means the job fires only when minute=0, hour=9, AND day-of-week=5 are all true at the same moment — once per week. Runs every Friday at 09:00 This is a typical pattern for weekly summary emails or report exports that need to be ready before employees start their workday.
Monthly invoice run on the 15th
Frequency: Monthly, Minute: 30, Hour: 14, Day of month: 15
The generator produces 30 14 15 * *. With day-of-month set to 15, the job fires mid-month regardless of what day of the week that date falls on. Runs on day 15 of every month at 14:30 A common trap here: if you also set a day-of-week value, most cron daemons interpret the two fields as OR logic rather than AND, running on the 15th of every month OR on whichever weekday you specified — potentially twice as often as intended. Leaving day-of-week as a wildcard avoids this.
Expert Unlock
The thing most explanations skip

The standard five-field cron format has a documented ambiguity in the day-of-month and day-of-week interaction: Vixie cron (the reference implementation) uses OR when both are specified as non-wildcards, but this is not universal. Cloud schedulers including AWS EventBridge and GCP Cloud Scheduler treat the same combination differently and document their own behavior explicitly — always verify against your specific platform's documentation rather than assuming POSIX behavior. A second edge case: some platforms count weeks differently from POSIX (ISO week numbering starts on Monday, POSIX week numbering starts on Sunday), and expressions built for one may fire on a different day on the other. When portability matters, stick to hour and minute as the only non-wildcard fields and handle all date-selection logic inside the job itself.

What does each field in my cron expression actually control?

What does the asterisk * mean in a cron expression?
An asterisk is a wildcard that matches every valid value in that field's range. In the minute field it means every minute from 0 through 59; in the day-of-week field it means any day. A fully wildcarded expression * * * * * runs every single minute. The asterisk is the most common cron character because most schedules want at least a few fields unrestricted.
Why does my weekly cron job run on the wrong day?
Day-of-week numbering is the most common source of confusion: Sunday is 0, Monday is 1, through Saturday as 6. If you enter 7 for Sunday many daemons accept it, but entering 7 for Saturday is wrong — Saturday is 6. Also check whether your cron implementation uses the OR rule for day-of-month and day-of-week simultaneously: if both fields are non-wildcard, many systems run the job when either condition is true, not both.
Can I run a cron job every 15 minutes using this tool?
The five-field POSIX cron format supports interval syntax using the slash character: */ 15 in the minute field means every 15 minutes (at : 00, : 15, : 30, : 45). This tool generates expressions based on your frequency preset and specific field values; for interval-based schedules like every 15 minutes, select Custom interval and type the slash expression directly into your crontab after copying the base expression. The slash syntax is standard across most Unix cron implementations including Vixie cron, cronie, and cloud schedulers.

Need something this doesn't cover?

Suggest a tool — we'll build it →