Cron Expression Generator: Practical Tips and Common Mistakes
Reviewed by the FreeOnline.fyi team · Updated
Key points
- Cron's five fields are minute, hour, day-of-month, month and day-of-week, and the minute always comes first.
- In standard cron, restricting both day-of-month and day-of-week makes the job run when either one matches.
- Quartz and AWS EventBridge add seconds and year fields, so a five-field string is not portable.
- Read the next five fire times in UTC as well as local time, because most schedulers run in UTC.
- Watch 01:00-03:00 local on clock-change days: spring-forward can skip a run and fall-back can double it.
What is a cron expression?
Cron schedules are written as a single line of five fields — minute, hour, day-of-month, month, day-of-week — where each field is a pattern rather than one fixed value. `0 9 * * 1-5` means 09:00 Monday through Friday, and `*/15 * * * *` means every fifteen minutes of every day. The minute comes first, which is the detail that trips up almost everyone the first time.
The Cron Expression Generator lets you build that line by clicking chips instead of typing it. Every row offers all values (`*`), a single number, a step (`*/5`), a range (`9-17`), a list (`1,15,30`) and named values such as JAN-DEC and SUN-SAT. Presets above the grid cover every minute, every 5 minutes, hourly, daily at 09:00, weekdays at 09:00, weekly Monday, monthly 1st and first day of quarter.
What you get back is three things at once: the expression rendered in standard, Quartz and AWS EventBridge dialects, a plain-English description of the schedule, and the next five fire times in your local timezone with the UTC equivalent alongside. It sits with the rest of the free, no-login utilities on FreeOnline.fyi.
What happens when both day fields are set?
In standard Vixie-style cron — the variant behind Linux crontab, GitHub Actions and Kubernetes CronJobs — restricting both day-of-month and day-of-week switches the logic to OR. So `0 0 1 * 0` fires at midnight on the 1st of the month *and* on every Sunday, which is rarely what the person writing it intended. The cron entry on Wikipedia documents this behaviour in the day-of-month and day-of-week fields.
Quartz and AWS EventBridge avoid the ambiguity by requiring `?` in one of the two day fields: you state whether you mean day-of-month or day-of-week, never both. That is why a five-field string with both fields filled in can produce a different schedule once you move it between platforms.
The fastest way to catch this is the next-five-runs list. If a job you believe is monthly shows four Sundays among its next five fire times, it is not monthly. Read that list before the expression reaches production.
Why does the same schedule break in Spring or EventBridge?
Field count and numbering change between schedulers. Standard cron has five fields and treats Sunday as both 0 and 7 in day-of-week. Quartz uses six or seven fields with seconds first, adds the `?` character, and numbers day-of-week so that 1 is Sunday. AWS EventBridge Scheduler also puts seconds first but appends a year field, and it numbers day-of-week from 1 as Sunday too.
Step syntax is the quieter trap. EventBridge reads a star inside a step value as zero, so `*/15` and `0/15` describe the same schedule there, and its month field takes numbers rather than names — use 1-12 rather than JAN-DEC. The AWS EventBridge Scheduler schedule-type documentation lists the exact allowed values for each field.
GitHub Actions sits at the other extreme: five fields only, evaluated in UTC, with a minimum interval of five minutes, so `* * * * *` will not run every minute there whatever the string suggests. The dialect tabs in the generator exist so you can view one visual schedule three ways and copy the version your target actually accepts.
Timezone and DST mistakes that skip a run
Most schedulers evaluate cron in UTC unless you tell them otherwise, which is why the tool always prints the UTC equivalent next to your local times. A 09:00 job in Berlin is 08:00 UTC in winter and 07:00 UTC in summer, and the engineer debugging it at 06:00 UTC is reading a different clock entirely.
That drift matters for jobs such as a daily FX-rate fetch: if the run is meant to land after the European close, the same expression shifts by an hour when the clocks change. If you need to check a rate by hand, the Live Currency Converter is a quick cross-check.
Daylight saving is where schedules genuinely misbehave. On a spring-forward day a job pinned to 02:30 local may never fire, because that wall-clock time does not exist; on the autumn fall-back it can fire twice because 01:30 happens twice. Vixie cron has some handling for this and other platforms differ, so keep business-critical jobs out of the 01:00-03:00 local window or schedule them in UTC.
Changing the timezone selector recomputes the next-five-runs list instantly. If a run vanishes or repeats around a DST date, the schedule is telling you something useful.
Common cron mistakes to check before you deploy
Confusing `*/5` with `0/5` is the most frequent error. `*/5` in the minute field runs at 0, 5, 10 and so on up to 55, which is what "every five minutes" normally means. A bare `5` runs once an hour at minute five. If you want every five minutes starting at minute two, write `2/5`.
Day-of-month arithmetic catches people out as well. `0 0 31 * *` only fires in months that have a 31st, so it skips February, April, June, September and November. `0 0 29 2 *` is a leap-day job whose next run can be years away — the next-five-runs list makes that painfully visible rather than surprising you later.
Special characters are dialect-specific. Quartz supports `L` for last, `W` for nearest weekday and `#` for the nth weekday of a month, which is how you express "the third Friday" or "the last day of the month". Standard cron and EventBridge do not, so those expressions are rejected or misread outside Quartz. Build them in the Quartz tab and confirm the plain-English description matches the sentence you had in mind.
How do you build and verify a schedule in under a minute?
Start from a preset rather than an empty grid. Daily at 09:00, weekdays at 09:00, monthly 1st and first day of quarter cover most production jobs. Adjust one row at a time and watch the description change; if the English no longer matches what you meant to say, the expression is wrong and you have found out cheaply.
If you are editing something that already exists, paste it first. The generator accepts a five-field crontab string, a six- or seven-field Quartz string and macros such as `@daily` and `@hourly`, parses it back into the visual rows, and shows an inline field-level error without disturbing your current schedule if the input is invalid. There is no login and nothing is uploaded, so pasting an internal schedule does not hand it to a third party.
Then pick the dialect tab, copy the expression, and read the next five fire times twice — once in your local timezone and once in UTC. If both lists look dull and expected, with no surprise Sundays, no leap-year gaps and no missing DST hours, paste it into the scheduler. As with any generated value, confirm the first real execution in your platform's own console before you depend on it.
Frequently asked questions
Is the Cron Expression Generator free, and does it need an account?
It is free and requires no account, no email and no sign-in. Everything runs in your browser, so the expression is parsed and the next-run times are calculated locally without sending anything to a server. That makes it practical for work schedules you would rather not paste into a third-party service.
Should I use the standard, Quartz or AWS EventBridge dialect?
Pick the dialect your target platform documents. GitHub Actions and Kubernetes CronJobs use the standard five-field form; Spring and Quartz use six fields with seconds first and a `?` in one day field; AWS EventBridge Scheduler uses six fields with a trailing year and also requires `?`. Copying the wrong dialect is a common cause of a job that silently never fires.
Why does a cron job not run on daylight saving changeover days?
Because the local wall-clock time it targets may not exist or may occur twice. On spring-forward, a job set for 02:30 local in a zone that jumps from 02:00 to 03:00 has no 02:30 that day. On fall-back the hour repeats and some schedulers fire twice. Schedule critical jobs in UTC or outside 01:00-03:00 local.
Can the Cron Expression Generator explain a cron expression I already have?
Yes. Paste the expression into the optional input and the tool parses it back into the five visual rows, then prints a plain-English description and the next five fire times. It accepts standard five-field strings, Quartz six- and seven-field strings and macros such as @daily. Invalid input shows an inline error and leaves your current schedule untouched.
Are the next five run times shown by the tool exact?
They are computed from your browser clock and the timezone you select, so they follow cron logic accurately, including February lengths and leap-year edge cases. What they cannot know are platform-specific rules, such as GitHub Actions ignoring intervals shorter than five minutes. Verify the first real execution in the target system before relying on the schedule.