Understanding Cron Jobs: How to Read and Write Schedules
Published 2026-05-10
Behind almost every recurring automated task — nightly backups, hourly data syncs, the weekly report that lands in your inbox every Monday — there is usually a cron job. Cron is the time-based scheduler that has run the Unix world since the 1970s, and its compact syntax now appears far beyond Unix: in GitHub Actions, Kubernetes, cloud functions, and CI pipelines. Learning to read it is a genuinely useful skill.
The five fields
A standard cron expression is five fields separated by spaces. Each field controls one unit of time:
* * * * *
| | | | |
| | | | +-- day of week (0-7, 0 and 7 = Sunday)
| | | +----- month (1-12)
| | +-------- day of month (1-31)
| +----------- hour (0-23)
+-------------- minute (0-59)
An asterisk (*) means "every value." So * * * * * means "every minute of every hour of every day" — the most frequent schedule cron allows.
The special characters
Each field accepts more than just a number or an asterisk:
- Comma for lists:
0,15,30,45in the minute field means at 0, 15, 30, and 45 minutes past the hour. - Hyphen for ranges:
1-5in the day-of-week field means Monday through Friday. - Slash for steps:
*/15in the minute field means every 15 minutes;*/2in the hour field means every other hour.
Reading real examples
0 9 * * 1-5 → at 09:00, Monday to Friday
*/15 * * * * → every 15 minutes
0 0 1 * * → at midnight on the 1st of every month
30 3 * * 0 → at 03:30 every Sunday
0 */6 * * * → every 6 hours (00:00, 06:00, 12:00, 18:00)
The pattern to internalize: read the fields left to right as minute, hour, day-of-month, month, day-of-week, and translate each special character. With a little practice, 0 9 * * 1-5 reads instantly as "9 AM on weekdays."
The timezone gotcha that causes outages
Here is the mistake that has broken countless production systems: classic cron has no timezone field. A job runs in whatever timezone the host machine is set to. Most servers run in UTC, so a job you scheduled for "9 AM" fires at 9 AM UTC — which might be 10 or 11 AM where you live, and shifts by an hour when daylight saving time changes.
If a scheduled report arrives an hour "late" twice a year, this is almost always why. When precise local timing matters, either set the schedule in UTC deliberately, or use a scheduler that supports an explicit timezone.
The day-of-month and day-of-week trap
One more surprise: when you set both the day-of-month and the day-of-week fields, standard cron combines them with OR, not AND. So 0 0 13 * 5 does not mean "midnight on Friday the 13th" — it means "midnight on the 13th of every month, and midnight every Friday." If you only want one of the two conditions, leave the other as *.
Test before you deploy
Because a single wrong character can mean a backup that silently never runs, always verify a cron expression before trusting it. The parser below translates any expression into plain English and shows the next several run times, so you can confirm a schedule does exactly what you intended.