Quick answer
A cron expression is five fields separated by spaces (minute, hour, day of month, month and day of week) that tell a scheduler when to run a job. For example, 0 9 * * 1-5 means 09:00 every Monday to Friday. Playxoft's free Cron Expression Generator builds expressions field by field, explains them in plain English, lists the next runs in any time zone and writes matching config for crontab, GitHub Actions, Kubernetes and other schedulers.
- Plain-English explanation
- Field-by-field builder
- Next runs in any time zone
- Daylight saving aware
- Seven platform snippets
- Shareable links
- Seconds field
How to use the Cron Expression Generator
- 1Type or paste an expression into Cron expression, or start from a preset such as Every 5 minutes or Weekdays at 9am.
- 2Click a field and use Build it field by field to choose Every, Specific values, a Range or a Step. The expression updates as you click.
- 3Read the plain-English sentence, then check Next runs in your time zone. Runs moved by daylight saving time are flagged.
- 4Turn on Seconds field if your scheduler uses a sixth field for seconds, such as Spring, Quartz or node-cron.
- 5Open Use it on your platform, pick crontab, GitHub Actions, Kubernetes, Cloudflare, Vercel, AWS or systemd, and copy the snippet.
- 6Use the link button to share the exact schedule and time zone with your team.
What is the cron expression format?
Cron is the Unix job scheduler, and a cron expression is the schedule part of a crontab line: five fields separated by spaces. A job runs whenever the current time matches every field.
┌───────────── minute 0–59
│ ┌─────────── hour 0–23
│ │ ┌───────── day of month 1–31
│ │ │ ┌─────── month 1–12 or JAN–DEC
│ │ │ │ ┌───── day of week 0–7 or SUN–SAT (0 and 7 are Sunday)
│ │ │ │ │
0 9 * * 1-5 /path/to/command| Field | Allowed values | Example | Meaning |
|---|---|---|---|
| Minute | 0–59 | 30 | At half past |
| Hour | 0–23 (24-hour clock) | 9-17 | 09:00 through 17:00 |
| Day of month | 1–31 | 1,15 | The 1st and the 15th |
| Month | 1–12, JAN–DEC | */3 | January, April, July, October |
| Day of week | 0–7, SUN–SAT | 1-5 | Monday to Friday |
Many schedulers also accept macros: @hourly (0 * * * *), @daily or @midnight (0 0 * * *), @weekly (0 0 * * 0), @monthly (0 0 1 * *), @yearly or @annually (0 0 1 1 *), and @reboot, which runs once when the cron daemon starts. GitHub Actions is one scheduler that rejects macros, so write the five fields there.
Spring and Quartz use six fields with seconds first, and Quartz also needs ? in one day field (0 0 9 ? * MON-FRI). node-cron accepts an optional seconds field. Browse ready-made schedules in the cron schedule library, and check the syntax your platform documents: crontab(5) for Linux, or the guides linked in the time zone table below.
What do *, /, - and , mean in cron?
Four characters do almost all the work. They combine freely, so 0,30 9-17/2 * * * is valid.
| Character | Name | Example | Matches |
|---|---|---|---|
* | Any value | * in hour | Every hour |
, | List | 0,30 in minute | :00 and :30 |
- | Range (inclusive) | 1-5 in day of week | Monday to Friday |
/ | Step | */15 in minute | :00, :15, :30, :45 |
A step counts from the start of its range: */15 starts at 0, 5-59/15 gives :05, :20, :35 and :50. Steps restart at every boundary, so */7 in the minute field runs at :56 and then again at :00, only four minutes later.
Put a step after * or a range, never after a single number. 0/15 means "every 15 minutes from 0" in Quartz, Spring, Kubernetes and EventBridge, but Vixie cron and cronie (Linux crontab) reject it. */15 or 0-59/15 works everywhere.
Some schedulers add characters standard cron does not have: L (last day), W (nearest weekday), # (nth weekday) and ? (no specific value). Quartz, Spring and AWS EventBridge accept all four. Cloudflare Workers accepts L, W and # but not ?, and Kubernetes treats ? like *. Linux crontab and GitHub Actions accept none of them. Watch the weekday numbers in #: Quartz, EventBridge and Cloudflare count Sunday as 1, so the second Monday is 2#2. The last day of the month and first Monday of the month pages show the portable workarounds.
How do day of month and day of week combine?
This is cron's most surprising rule. When both day fields are restricted, cron runs when either one matches, not both. So 0 0 1 * 1 runs at midnight on the 1st of every month and on every Monday.
That is why 0 0 1-7 * 1 does not mean "the first Monday of the month": it runs on days 1 to 7 and on every Monday. The reliable fix is to schedule days 1–7 and test the weekday in the command (escape % inside crontab), as the first Monday of the month page explains:
0 9 1-7 * * [ "$(date +\%u)" = 1 ] && /path/to/first-monday.shThere is one more twist in Vixie cron and cronie: a day field that starts with * counts as unrestricted, even */2. So 0 0 */2 * 1 runs only on odd-numbered days that are also Mondays. Other implementations disagree on this edge case, so this tool follows cronie (what most Linux servers run) and warns you when it applies.
How do time zones and daylight saving time affect cron jobs?
A cron expression has no time zone of its own. It runs in whatever zone the scheduler uses, and several popular platforms default to UTC or only support UTC:
| Platform | Time zone | Daylight saving |
|---|---|---|
| Linux crontab | Server's zone; CRON_TZ= per crontab in cronie | Follows local clock changes (see below) |
| GitHub Actions | UTC by default; add timezone: (IANA name) next to each cron entry | Follows the named zone; a run in the skipped hour moves to the next valid time |
| Kubernetes CronJob | spec.timeZone (any IANA name, 1.27+), else the controller's zone | Follows the named zone |
| Cloudflare Workers | UTC only | None |
| Vercel Cron Jobs | UTC only | None |
| AWS EventBridge Scheduler | Any IANA zone | Follows the named zone |
| AWS EventBridge scheduled rules (legacy) | UTC only | None |
| systemd timers | Server's zone, or a zone written after the time in OnCalendar= | Follows the named zone |
In a zone with daylight saving time, one night a year skips an hour and another repeats one. Cronie handles both: a job at a fixed time inside the skipped hour (say 30 2 * * * in New York) runs once, right after the clocks jump; in the repeated hour it runs only once. Jobs with * in the minute or hour field follow the wall clock instead, so they lose the skipped runs and repeat the doubled hour. The Next runs list in the generator shows these cases for any zone you pick. The safest habit: run servers in UTC, and avoid scheduling local jobs between 01:00 and 04:00, the window where the US, Western Europe and Eastern Europe change their clocks.
What are the most common cron mistakes?
- Every minute by accident.
* * * * *runs 1,440 times a day. Hourly is0 * * * *. - Steps in the wrong field.
*/2 * * * *is every 2 minutes; every 2 hours is0 */2 * * *. - Assuming the server's time zone. Most cloud servers and CI runners use UTC, so
0 9 * * *may fire at 4 or 5 in the morning New York time. - A step after a single number.
0/15works in Quartz and Kubernetes, but Linux crontab rejects it; write*/15. - Unescaped `%`. In a crontab line,
%ends the command and starts its input. Writedate +\%F. - A different environment. Cron runs with a minimal
PATHand no shell profile. Use absolute paths and set variables at the top of the crontab. - Overlapping runs. Cron starts the next run even if the last one is still going. Use
flock -n /tmp/job.lock command. - Silent failures. Output is mailed to the crontab owner and often lost. Redirect it to a log and alert when a job stops checking in.
Cron vs systemd timers vs cloud schedulers: which should I use?
All three read similar schedules; they differ in what happens around the run.
| cron | systemd timers | Cloud schedulers | |
|---|---|---|---|
| Best for | Simple jobs on one Linux machine | Server jobs that need logs and catch-up | Serverless apps, CI, Kubernetes |
| Missed runs while down | Skipped | Run at boot with Persistent=true | Depends on the provider |
| Logs | Mail, or your own redirect | journald: journalctl -u job | Provider console |
| Seconds | No | Yes | Usually no (1-minute minimum) |
| Time zones | Server zone (CRON_TZ in cronie) | Any zone in OnCalendar= | UTC on Cloudflare and Vercel; GitHub Actions, Kubernetes and EventBridge Scheduler accept a zone |
| Overlap control | Do it yourself with flock | Won't start a unit that is still running | concurrencyPolicy in Kubernetes |
Use cron for quick jobs on a box you manage, systemd timers when reliability and logging matter on that box, and your platform's scheduler when the job lives in the cloud. Whichever you pick, this generator writes the syntax for you.
Frequently asked questions
Last updated by the Playxoft engineering team.