</>DevTools

CRNCron Expression

Parse and explain cron expressions

Every 5 minutes
*/5
Minute
*
Hour
*
Day (month)
*
Month
*
Day (week)

Presets

Reading and Writing Cron Expressions, Timezone Traps Included

A cron expression describes a recurring schedule in five (or six) fields. The format is simple, but a wrong expression shows up either as 'nothing ever happens' or 'it runs far more often than intended' — symptoms you usually discover after deploying. This tool turns an expression into a plain-language sentence so you catch the misunderstanding first.

Field layout

Some implementations add a seconds or year field — Quartz (Java) and AWS EventBridge among them. Pasting a six-field expression into a five-field cron shifts every field by one and yields a completely different schedule, so check your target's dialect first.

Standard five-field cron
┌───────────── minute (0-59)
│ ┌─────────── hour (0-23)
│ │ ┌───────── day of month (1-31)
│ │ │ ┌─────── month (1-12 or JAN-DEC)
│ │ │ │ ┌───── day of week (0-6 or SUN-SAT, 0=Sunday)
│ │ │ │ │
* * * * *

Special characters

SymbolMeaningExample
*Every value* * * * * → every minute
,List of values0 9,18 * * * → 09:00 and 18:00 daily
-Range0 9-18 * * * → hourly from 09:00 to 18:00
/Step*/15 * * * * → every 15 minutes
range + stepStep within a range0 9-18/2 * * * → 9, 11, 13, 15, 17
LLast (some implementations)0 0 L * * → last day of the month
WNearest weekday (some implementations)0 0 15W * * → weekday nearest the 15th
#Nth weekday (some implementations)0 0 * * 1#2 → second Monday

How to use it

  1. Enter a cron expression to see a human-readable description.
  2. Read the description and confirm it matches your intent — pay special attention if it says 'every minute'.
  3. Try several candidate expressions back to back to converge on the shape you want.
  4. Move the final expression into your crontab or CI configuration.

Commonly used expressions

ExpressionMeaning
*/5 * * * *Every 5 minutes
0 * * * *Every hour on the hour
0 */2 * * *Every 2 hours on the hour
0 3 * * *Daily at 03:00
30 2 * * 1-5Weekdays at 02:30
0 0 * * 0Sundays at midnight
0 0 1 * *First of the month at midnight
0 0 1 1 *January 1st at midnight
0 9 * * 1Mondays at 09:00
*/30 9-18 * * 1-5Every 30 minutes, 09:00–18:00, weekdays

Day-of-month and day-of-week combine as OR

This is the rule people get wrong most often. When both the day-of-month (third) and day-of-week (fifth) fields are set to something other than *, standard cron ORs them rather than ANDing them. So 0 0 13 * 5 does not mean 'the 13th when it's a Friday' — it means 'the 13th, or any Friday', and it fires on both.

Expressing 'only on Friday the 13th' in a single standard cron expression is impossible. In practice you schedule the job daily and check the date inside the script, exiting early when it doesn't apply. That approach also scales as the condition gets more complicated.

Timezones and daylight saving

Cron follows the timezone of the environment it runs in, and most container images default to UTC — so a batch job you set for 03:00 locally may run at midday in production. To express 03:00 Korean time in UTC you subtract nine hours and write 18:00 the previous day (0 18 * * *).

In regions that observe daylight saving, subtler problems appear: on the spring-forward day a nonexistent hour causes jobs scheduled in it to be skipped, and on the fall-back day the same hour passes twice, so a job may run twice. Korea doesn't observe DST, but you'll meet this if your jobs live in a US or European region. The pragmatic workaround is to avoid scheduling anything between 02:00 and 03:00.

Making cron jobs safe

  • Prevent overlap: if the previous run hasn't finished when the next tick arrives, two copies run concurrently. Use flock or an application-level lock.
  • PATH differences: cron's environment isn't your login shell's. Use absolute paths or set PATH inside the script — this is the cause of most 'works locally, fails under cron' reports.
  • Handle output: anything on stdout piles up as system mail. Redirect with >> /var/log/job.log 2>&1.
  • Escape %: in a crontab, % means a newline, so commands like date +%Y need \%.
  • Failure alerting: cron fails silently. Check exit codes and notify, or push a completion ping to a health-check service (a dead man's switch).
  • Idempotency: designing jobs so a second run produces the same result makes retries and accidental overlap far less dangerous.

Frequently Asked Questions

Does */7 * * * * really run every 7 minutes?
No. The step is computed within the field's range (0–59), so it fires at minutes 0, 7, 14, 21, 28, 35, 42, 49, and 56 — and the gap from 56 to the next hour's 0 is only 4 minutes. Any step that isn't a divisor of 60 (5, 10, 15, 20, 30) breaks at the hour boundary. If you need exact intervals, use a queue or a scheduler's interval feature instead.
Is Sunday 0 or 7 in the day-of-week field?
The standard is 0. Many implementations, Vixie cron included, also accept 7 for compatibility, but not all do. Using names like SUN and MON removes the ambiguity entirely.
What are shorthands like @daily?
Convenience aliases offered by some implementations: @yearly (0 0 1 1 *), @monthly (0 0 1 * *), @weekly (0 0 * * 0), @daily (0 0 * * *), @hourly (0 * * * *), plus @reboot which runs once at boot. They read well but aren't universally supported, so verify on your platform.
What happens on the 31st in February?
Dates that don't exist that month are simply skipped, so 0 0 31 * * only runs in months that have a 31st — never in February, April, June, September, or November. For 'last day of the month', use 0 0 L * * where L is supported, or run daily and check in the script whether tomorrow is the 1st.
Do jobs missed while the server was off run later?
Standard cron simply misses them. anacron, or a systemd timer with Persistent=true, will run missed jobs after boot — which is what you want on machines that aren't always on, such as laptops.
What if I need sub-minute scheduling?
Standard cron's finest granularity is one minute. For anything shorter, use a scheduler with a seconds field such as Quartz, run a short loop inside a per-minute job, or reconsider the design in favor of a long-running process with a queue.

💡 Note: Before shipping an expression, read this tool's description of it out loud. An interpretation as wrong as 'every minute' becomes obvious the moment you say it.

🔗Related Tools💻 Regex / Code