FlexKit
Blog
Buy us a shawarma!
Guides
18 min read

Cron Expressions Explained in Plain English

Published on March 15, 2026

How to read and write cron expressions for scheduling tasks (e.g. “every day at 2am” or “every 5 minutes”).

The five (or six) fields of a cron expression

A standard cron expression has five fields: minute, hour, day of month, month, day of week. Order is: minute hour day month weekday. For example 0 2 * * * means “at minute 0 of hour 2, every day of month, every month, every day of week”—i.e. 2:00 AM daily.

Each field can be a number, a range (e.g. 1-5), a list (e.g. 1,3,5), or a step (e.g. */5 for “every 5”). The asterisk * means “every.” So */15 in the minute field means “every 15 minutes.” 0 9-17 * * 1-5 means “every hour from 9 to 17, on weekdays”—like business hours.

Some systems use a sixth field for seconds at the start. Then you have: second minute hour day month weekday. Check your scheduler (e.g. Spring, node-cron) for the exact format. An online cron explainer can help: paste your expression and see “runs at…” in plain language.

Day of week can be 0–6 (Sunday–Saturday) or 1–7 (Monday–Sunday) depending on the system. Some cron implementations allow 7 for Sunday when using 1–7. When in doubt, test with an explainer or the scheduler’s documentation. Mixing up 0 and 7 is a common source of “why is my job not running?” bugs.

Month numbers are 1–12 (January–December). Day of month is 1–31. Not every month has 31 days; cron usually runs on the last valid day or skips (implementation-dependent). For “last day of month” you may need a scheduler that supports special characters (e.g. L in Quartz) or a wrapper script.

Common patterns and how to write them

"Every day at midnight" is 0 0 * * *. "Every hour" is 0 * * * *. "Every 30 minutes" is */30 * * * *. "Weekdays at 9am" is 0 9 * * 1-5 (Monday–Friday in 0–6 systems; check your scheduler for Sunday = 0 vs 7).

"First day of every month at 3am" is 0 3 1 * *. "Last day of every month" is trickier—cron does not have "last day" built in. You often need a wrapper script or a scheduler that supports L (e.g. in Quartz). For "every Monday at 10am" use 0 10 * * 1.

"Every 5 minutes" is */5 * * * *. "Every 2 hours" is 0 */2 * * *. The step value must divide the range evenly in some implementations (e.g. */5 for minutes is fine; */7 for minutes might not run as you expect on all systems). Test or read your scheduler’s docs.

"At 9:00 and 17:00 every day" is 0 9,17 * * *. Use a comma to list specific values. "At 0 minutes past every hour from 9 to 17" is 0 9-17 * * *. Ranges and lists can be combined in some systems (e.g. 0 9-17 * * 1-5 for weekdays only).

"Every 10 minutes during business hours" might need two expressions or a single expression depending on the scheduler. 0 9-17 * * * with */10 in the minute field is not standard (minute would run every 10 min but hour would still be 9–17). Typically you write */10 9-17 * * * to get “every 10 minutes when hour is 9–17.”

Pitfalls and time zones

Month and weekday names are not always supported. Numbers are safest: 1–12 for months, 0–6 or 1–7 for weekdays depending on the tool. When in doubt, use numbers and an explainer to verify.

Time zones matter. Cron usually runs in the server’s local time (or a configured TZ). "0 2 * * *" is 2 AM in that timezone. For UTC, set TZ=UTC in the environment or use a scheduler that lets you set the timezone explicitly. Misconfigured time zones cause jobs to run at the "wrong" time.

Day of month and day of week can both be set. When both are restricted (e.g. 0 9 15 * 1), some crons run when either condition matches; others use "and." This is implementation-dependent. For clarity, avoid mixing day-of-month and day-of-week unless you know your scheduler’s behavior. Prefer one or the other for a given job.

Daylight saving time can shift local time. A job set for 2 AM might run twice (when clocks fall back) or be skipped (when clocks spring forward) if the scheduler uses local time. For critical schedules, use UTC or a scheduler that handles DST explicitly.

Spaces and field order matter. Five fields must be in order: minute, hour, day of month, month, day of week. An extra space or wrong order can make the expression invalid or change its meaning. Use an explainer to validate.

Using an online cron explainer

An online tool that explains cron expressions is useful when learning or debugging. You paste an expression (e.g. 0 */6 * * *) and see "runs at 00:00, 06:00, 12:00, 18:00 every day" or a list of next run times. That confirms you wrote what you meant.

Some explainers support "extended" or "Spring" format with a seconds field or special characters (e.g. L for last day). If your job runs in Spring or another framework, use an explainer that matches that format so the interpretation is correct.

When a job does not run as expected, double-check the expression in an explainer. Typos (e.g. a space too many, wrong order of fields) are common. So is forgetting that the server is in a different time zone than you. Verifying the expression and the server’s TZ saves a lot of head-scratching.

Use the explainer to generate expressions from plain language if the tool supports it. For example, "every weekday at 9am" might be translated to 0 9 * * 1-5. Then you can copy the expression into your scheduler.

Keep the explainer bookmarked. When you add a new job or inherit a codebase with cron jobs, pasting each expression into the explainer gives you a quick human-readable summary and catches mistakes before they go to production.

Where cron runs: systems and alternatives

Traditional cron lives on Unix-like systems (Linux, macOS). You edit crontab with crontab -e and the system runs jobs at the specified times. The same five-field syntax is used by many cloud schedulers (e.g. AWS EventBridge, Google Cloud Scheduler) and libraries (e.g. node-cron, Spring @Scheduled).

Cron is not always the right tool. For "run every 5 seconds" or "run when this event happens," you need a different mechanism (e.g. a loop with sleep, or an event-driven system). Cron is for calendar-based schedules: minute, hour, day.

If your app runs in a container or serverless function, cron might be external (e.g. a cloud scheduler triggers the function at a fixed schedule). The expression format is often the same; only the execution environment differs. Check your platform’s docs for the exact syntax and time zone behavior.

Log and monitor cron jobs. A job that fails silently is hard to debug. Send output to a log file or monitoring system, and set up alerts for failures. Knowing when a job last ran successfully is as important as writing the expression correctly.

cron
scheduling
automation
syntax

Read more articles on the FlexKit blog