Cron expression for every 45 minutes
Every 45 minutes, counted from midnight.
Next 10 runs
In Cron, worked out in your browser from the current time.
At a glance
- Runs
- 32 a day
- Gap between runs
- Always 45 minutes
- Expressible in
- All six dialects
- Clock changes
- Affected in New York, London, Berlin, Helsinki, Sydney
In each dialect
Every expression here is generated by the tester’s own engine and checked run for run against the others, so “Exact” means the same clock times in the same zone. Each one links to the tester.
0,45 */3 * * * /path/to/command
30 1-23/3 * * * /path/to/command
15 2-23/3 * * * /path/to/command- Add all 3 lines to the crontab.
aws events put-rule --name every-45-minutes --schedule-expression "cron(0,45 0/3 * * ? *)"
aws events put-rule --name every-45-minutes --schedule-expression "cron(30 1/3 * * ? *)"
aws events put-rule --name every-45-minutes --schedule-expression "cron(15 2/3 * * ? *)"- Wrap it in
cron(…). Day of week is?because day of month already holds*, and a*in both is rejected. The final*is the required year field. - Create one rule per expression, each with the same target. A single
rate(45 minutes)also works, but it counts from when the rule is created, not from midnight.
CronScheduleBuilder.cronSchedule("0 0,45 0/3 * * ?")
CronScheduleBuilder.cronSchedule("0 30 1/3 * * ?")
CronScheduleBuilder.cronSchedule("0 15 2/3 * * ?")- The leading
0is the seconds field, so it fires at the top of the minute. Day of week is?because day of month already holds*, and a*in both is rejected. The optional year is left off. - Attach one
CronTriggerper expression to the same job.SimpleScheduleBuilder.repeatMinutelyForever(45)is the one-trigger alternative, counted from the trigger’s start time.
schedule: "0,45 */3 * * *"
schedule: "30 1-23/3 * * *"
schedule: "15 2-23/3 * * *"- A CronJob takes one schedule, so this needs 3 CronJobs sharing a job template.
- If a Job can run longer than 45 minutes, the next one starts alongside it by default.
concurrencyPolicy: Forbidskips the new run instead, andReplacestops the old one. - The controller stops starting a CronJob that has missed more than 100 schedules. At this rate that is 75 hours of downtime.
startingDeadlineSecondslimits how far back it counts.
- cron: '0,45 */3 * * *'
- cron: '30 1-23/3 * * *'
- cron: '15 2-23/3 * * *'- GitHub warns that schedules can be delayed at high load, which includes the start of every hour, and that some queued jobs may be dropped. A different minute reduces the risk.
- List all 3 under
schedule:in one workflow.github.event.scheduletells a step which one fired.
[TimerTrigger("0 0,45 */3 * * *")]
[TimerTrigger("0 30 1/3 * * *")]
[TimerTrigger("0 15 2/3 * * *")]- Six fields with seconds first, so the leading
0fires at the top of the minute. - A timer trigger takes one expression, so this needs 3 functions. On an App Service plan, the TimeSpan
00:45:00is the single-trigger alternative, measured between runs rather than from midnight.
About this schedule
The obvious */45 is a trap: in the minute field it means minutes 0 and 45, so runs come 45 minutes apart and then 15. A true 45-minute cycle repeats every three hours (00:00, 00:45, 01:30, 02:15, 03:00), so cron needs three lines, one for each position in that cycle. Because 45 minutes divides a day exactly, the pattern restarts cleanly at midnight.
Clock changes
Worked out by running each dialect’s engine through New York’s clock changes; it is affected in London, Berlin, Helsinki, Sydney too, at their own local hours.
| Dialect | Clocks go forward (02:00 becomes 03:00) | Clocks go back (02:00 becomes 01:00) |
|---|---|---|
| Cron | 02:15 doesn’t exist that day, so it’s skipped | 01:30 happens twice, and it runs both times |
| EventBridge Scheduler | 02:15 doesn’t exist that day, so it’s skipped | 01:30 happens twice, and it runs once, in the first pass |
| Quartz | 02:15 doesn’t exist that day, so it’s skipped | 01:30 happens twice, and it runs once, in the second pass |
| Kubernetes | 02:15 doesn’t exist that day, so it’s skipped | 01:30 happens twice, and it runs both times |
| GitHub | 02:15 doesn’t exist that day. GitHub moves it to 03:00, where it is counted once with the 03:00 run | 01:30 happens twice. GitHub doesn’t document whether it repeats; shown once here |
| Azure | 02:15 doesn’t exist that day, so it runs at 03:15 | 01:30 happens twice, and it runs both times |
Cron follows the crontab man page; daemons differ, and cronie catches up skipped fixed-time jobs. EventBridge applies to Scheduler with a time zone; scheduled rules run in UTC and never see a clock change. Quartz is exact for 2.5.2. GitHub documents the forward case only.
Questions
- What is the cron expression for every 45 minutes?
- It takes 3 lines, used together:
0,45 */3 * * *,30 1-23/3 * * *,15 2-23/3 * * *in standard cron, Kubernetes and GitHub Actions. The other dialects differ:0,45 0/3 * * ? *,30 1/3 * * ? *,15 2/3 * * ? *in EventBridge;0 0,45 0/3 * * ?,0 30 1/3 * * ?,0 15 2/3 * * ?in Quartz;0 0,45 */3 * * *,0 30 1/3 * * *,0 15 2/3 * * *in Azure. - Why doesn’t
*/45run every 45 minutes? - A step only counts within one field and restarts each hour. In the minute field,
*/45is minutes 0 and 45, so the gaps alternate between 45 and 15 minutes. The three lines on this page give a steady 45-minute gap. - What happens to this schedule when the clocks change?
- It depends on the scheduler. When clocks go forward in New York (02:00 becomes 03:00): Cron, EventBridge, Quartz and Kubernetes: 02:15 doesn’t exist that day, so it’s skipped. GitHub: 02:15 doesn’t exist that day. GitHub moves it to 03:00, where it is counted once with the 03:00 run. Azure: 02:15 doesn’t exist that day, so it runs at 03:15. The table on this page also covers the autumn change.