Closest cron expression
*/45 * * * *
At 0 and 45 minutes past the hour. On its own, it runs 48 times a day, 17,520 times a year.
This is a classic cron trap. */45 in the minute field means “minutes divisible by 45”, which is only :00 and :45. So */45 * * * * runs at 10:00, 10:45, 11:00, 11:45, with gaps that alternate between 45 and 15 minutes. Steps restart every hour, so no single cron line runs every 45 minutes.
Workaround: run a job every 45 minutes
Run every 15 minutes and let the command skip two out of three runs, based on the number of minutes since the Unix epoch. In a crontab, % must be escaped as \%.
*/15 * * * * [ $(( $(date +\%s) / 60 \% 45 )) -lt 15 ] && /usr/local/bin/job.sh
The same idea works on every scheduler below: keep the base schedule and put the check at the start of the job’s command or script.
Field by field
| Field | Value | Matches |
|---|---|---|
| minute | */45 |
0, 45 |
| hour | * |
every value |
| day of month | * |
every value |
| month | * |
every value |
| day of week | * |
every value |
Examples
crontab
Run crontab -e and add:
*/45 * * * * /usr/local/bin/job.sh >> /var/log/job.log 2>&1
For the exact schedule, use the workaround line above instead.
Kubernetes CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: my-job
spec:
schedule: "*/45 * * * *"
timeZone: "Etc/UTC" # Kubernetes 1.27+
concurrencyPolicy: Forbid # skip a run if the last one is still going
jobTemplate:
spec:
template:
spec:
containers:
- name: job
image: ghcr.io/acme/job:1.0
restartPolicy: OnFailure
GitHub Actions
on:
schedule:
- cron: '*/45 * * * *' # UTC
GitHub evaluates schedules in UTC, and runs can start several minutes late at busy times.
systemd timer
# /etc/systemd/system/job.timer
[Unit]
Description=Run job.service every 45 minutes
[Timer]
OnCalendar=*-*-* *:00,45:00
Persistent=true
[Install]
WantedBy=timers.target
Enable it with systemctl enable --now job.timer, and check the next runs with
systemd-analyze calendar "*-*-* *:00,45:00". Persistent=true runs a missed job after
downtime, which cron can’t do.
AWS EventBridge
cron(0,45 * * * ? *)
EventBridge cron has six fields (the last is the year), uses ? in either the day-of-month or the
day-of-week field, and numbers weekdays from 1 (Sunday) to 7. Rules run in UTC; EventBridge Scheduler also
accepts a time zone.
Similar schedules: every few minutes
-
Every minute:
* * * * * -
Every 30 seconds:
* * * * * -
Every 2 minutes:
*/2 * * * * -
Every 3 minutes:
*/3 * * * * -
Every 5 minutes:
*/5 * * * * -
Every 10 minutes:
*/10 * * * * -
Every 15 minutes:
*/15 * * * * -
Every 20 minutes:
*/20 * * * * -
Every 30 minutes:
*/30 * * * * -
Every 5 minutes during business hours:
*/5 9-17 * * 1-5
Have a different schedule? Paste any expression into the Cron Expression Generator, or browse all cron examples.
Sources
- POSIX: crontab
- crontab(5) manual page
- Kubernetes docs: CronJob
- GitHub Actions docs: schedule event
- systemd.time(7): calendar events
- AWS docs: EventBridge Scheduler cron expressions
Spotted a mistake? Email hello@devtoolsmith.com and we’ll fix it.
Frequently asked questions
How do I run a cron job every 45 minutes?
No single standard cron expression does this exactly. This is a classic cron trap. */45 in the minute field means “minutes divisible by 45”, which is only :00 and :45. So */45 * * * * runs at 10:00, 10:45, 11:00, 11:45, with gaps that alternate between 45 and 15 minutes. Steps restart every hour, so no single cron line runs every 45 minutes. Run every 15 minutes and let the command skip two out of three runs, based on the number of minutes since the Unix epoch. In a crontab, % must be escaped as \%. */15 * * * * [ $(( $(date +\%s) / 60 \% 45 )) -lt 15 ] && /usr/local/bin/job.sh