Cron Expression Generator
Build cron expressions visually with presets.
What is a cron expression?
A cron expression is a five-field schedule string read by the classic Unix (Vixie) cron daemon. The fields, in order, are minute hour day-of-month month day-of-week. Each field accepts either a literal value, a wildcard, or one of the operators described below, and the daemon fires a job whenever the current wall-clock minute matches every field at once.
Worked example: 0 9 * * 1-5 resolves to "9:00 AM, Monday through Friday." Minute is 0, hour is 9, day-of-month and month are wildcards, and day-of-week is the range 1-5. Vixie cron predates 1980 and has remained the de-facto Unix scheduler across four decades of platform shifts. Modern systems from GitHub Actions to Kubernetes still parse the same five fields with only minor extensions.
Cron flavors and special characters
Three cron dialects dominate production systems, and each one counts fields differently. Mixing them up is the single most common reason a paste from Stack Overflow refuses to parse in the target scheduler.
Vixie cron uses five fields and is the dialect under classic crontab, GitHub Actions workflows, and Kubernetes CronJobs. Quartz uses seven fields, adding a leading seconds field and a trailing year field, and powers Spring Scheduler and the Quartz Java library. AWS EventBridge sits between the two with six fields (no seconds, but with year), and it explicitly disallows specifying both day-of-month and day-of-week in the same expression.
The operator alphabet also differs. Across all flavors, * matches any value, / defines a step, , joins a list, and - defines a range. Quartz adds four specials that Vixie does not understand: ? means "don't care" and is required when day-of-month and day-of-week are mutually exclusive, L means "last" (for example, last day of the month), W means "nearest weekday" to a given date, and # picks the nth weekday of the month (e.g., 2#1 for the first Monday). Our generator emits Vixie-style five-field output by default, which is the right target for the largest set of downstream schedulers.
Worked example, "every 15 minutes during business hours, weekdays only": */15 9-17 * * 1-5. Field one, */15, fires at minute 0, 15, 30, and 45 of every hour. Field two, 9-17, restricts to hours 9 through 17 inclusive. Fields three and four are wildcards, so the schedule applies on every day of every month. Field five, 1-5, restricts to Monday through Friday. The result is 36 fires per business day and zero fires on weekends.
Common pitfalls
Cron looks like a five-token string and feels trivially simple. The pitfalls below have all caused real production incidents, and they share one root cause: the expression appears to mean one thing in English while the scheduler reads it differently. We list the four that show up most often in postmortems.
- DST transitions are implementation-specific. A schedule like
30 2 * * *can fire twice on fall-back days and skip entirely on spring-forward days, depending on the daemon. Linux cron, systemd timers, and Quartz each pick a different recovery rule, and none of them is portable. Schedule in UTC if timing matters; the timezone never shifts and the rule stays predictable across deploys. - The wildcard schedule
* * * * *runs every single minute. It is also the easiest expression to paste accidentally from a tutorial. A job hooked up that way against a downstream service with a 200ms latency floor will issue 1,440 requests per day and surface as a load anomaly long before it surfaces as a scheduling bug. - Specifying both day-of-month and day-of-week in classic Vixie cron treats them as a logical OR.
0 0 1 * 1fires on the 1st of the month or on every Monday, not on Mondays that fall on the 1st. Quartz reads the same two fields as a logical AND and requires?in one of them to disambiguate. The bug stays invisible for weeks, then surfaces on the one date that exposes the OR. - Classic cron has no second-precision. Minimum granularity is one minute, and any expression that pretends otherwise is silently rounded. For sub-minute cadence, the right tools are Quartz (with its leading seconds field), systemd timers (with
OnUnitActiveSec), or an external scheduler such as Temporal or a queue-driven worker.
When to use this tool
We built the generator for three concrete workflows. The first is a backend developer wiring a GitHub Actions workflow to run a nightly data import: paste the desired English description, get a five-field expression that drops directly into the schedule: block, and avoid the off-by-one-hour bugs that plague hand-written cron. The second is an ops engineer setting up a Kubernetes CronJob for nightly database backups, where the spec.schedule field also expects Vixie syntax and the next-run preview confirms the job will actually fire when expected. The third is a cloud architect crafting an AWS EventBridge schedule to keep a Lambda warmer alive at low cost, where the six-field EventBridge dialect demands the day-of-month-vs-day-of-week disambiguation we call out above.
Frequently asked
- What's the difference between Vixie cron and Quartz?
- Vixie cron uses 5 fields (`minute hour day-of-month month day-of-week`) and powers classic Unix crontab, GitHub Actions workflows, and Kubernetes CronJobs. Quartz uses 7 fields (adds a leading `seconds` field and a trailing `year` field) and powers Spring Scheduler, the Quartz Java library, and most JVM scheduling stacks. Quartz also adds the `?`, `L`, `W`, and `#` characters that Vixie does not understand. AWS EventBridge sits in the middle: 6 fields with year, no `seconds`, with Quartz-style specials.
- Why does my cron job run at the wrong time?
- Three causes dominate. First, timezone: the cron daemon runs in the system timezone unless `TZ=UTC` is set in the crontab or the scheduler explicitly takes a TZ. Second, Daylight Saving Time: a `30 2 * * *` schedule misfires twice (spring forward) or fires twice (fall back) on transition days. Third, field-order swaps: Vixie is `min hour dom mon dow`, easy to confuse with `min hour mon dom dow` if reading half-asleep. Schedule in UTC if timing matters.
- How do I schedule for the last day of the month?
- Vixie cron has no `L` character, so the canonical workaround is to run nightly with a script-side check: `0 0 28-31 * * [ $(date -d tomorrow +%d) -eq 1 ] && /run/job`. Quartz handles it natively: `0 0 0 L * ?` fires at midnight on the last day. AWS EventBridge: `cron(0 0 L * ? *)`. Kubernetes CronJobs inherit Vixie semantics, so the script-side check is the only portable approach for k8s.
- Does my cron schedule respect Daylight Saving Time?
- Implementation-specific and a frequent foot-gun. Linux Vixie cron skips schedules in the DST spring-forward gap and fires duplicates in the fall-back overlap. Quartz fires once during fall-back, never during spring-forward. GitHub Actions runs entirely in UTC and simply does not have a DST concept. Kubernetes CronJobs use UTC by default and honor a `spec.timeZone` field since 1.27. We schedule everything time-sensitive in UTC and let display layers handle local conversion.
- What's the most-frequent schedule cron supports?
- Classic Vixie cron tops out at 1-minute granularity: `* * * * *` runs every minute and there is no smaller field. Quartz drops to 1 second via its leading seconds field: `*/10 * * * * ?` runs every 10 seconds. For sub-minute scheduling on Linux without Quartz, we reach for `systemd` timers (`OnCalendar=*:0/0:30` for 30 seconds) or external schedulers like Apache Airflow, Temporal, or AWS EventBridge with a 1-minute floor.