Every 45 Minutes Cron Expression
Step `*/45` — fires at minute 0 and minute 45, then resets each hour.
*/45 * * * * in POSIX cron
Expression
*/45 * * * *Try it in the tester →Field Breakdown
How It Works
Step `*/45` in the minute field matches 0 and 45 within the 0–59 range. The cadence is not a clean 45-minute interval — every hour the minute counter resets, so the gap between minute 45 of one hour and minute 0 of the next is only 15 minutes.
Example Run Times
- 12:00:00
- 12:45:00
- 13:00:00
- 13:45:00
- 14:00:00
Frequently Asked Questions
Why isn't this a true 45-minute interval?
Cron evaluates each field independently against a single time slot — it doesn't track elapsed time across boundaries. For a real 45-minute cadence, use a job scheduler with elapsed-time semantics (e.g. systemd timers with `OnUnitActiveSec=45m`) or chain `sleep 2700` inside the script.
*/45 * * * * in Quartz / Spring
Despite its name, this is not a uniform 45-minute schedule. In a 0-59 minute field, */45 matches only minutes 0 and 45, so the trigger fires at :00 and :45 of every hour — 48 times a day — with gaps that alternate between 45 minutes and 15 minutes as the minute counter resets each hour.
Quartz / Spring expression
0 */45 * * * ?Try it in the tester →At second 0, every 45 minutes, every hour
Unix / POSIX equivalent: */45 * * * *
Field Breakdown
Using It with Quartz / Spring
Treat this expression as "twice an hour, at :00 and :45" and it serves fine for jobs like staggered cache refreshes that deliberately avoid the half-hour mark. But most people searching for every-45-minutes want a true fixed interval, and cron's hour-scoped minute field can't provide one. In Quartz, reach for a SimpleTrigger built with withIntervalInMinutes(45); in Spring, use @Scheduled(fixedRate = 2700000) — both produce genuine 45-minute spacing measured from a start time, at 32 executions per day instead of 48.
Quartz-Specific Notes
- →Because 45 does not divide 60, the step truncates at the hour: after the :45 firing, the next match is the following hour's :00, only fifteen minutes later.
- →A true 45-minute grid repeats every three hours (LCM of 45 and 60 minutes). It can be expressed in cron, but only with four cooperating triggers: 0 0 0/3 * * ?, 0 45 0/3 * * ?, 0 30 1/3 * * ?, and 0 15 2/3 * * ? — at which point a SimpleTrigger is the saner choice.
- →Run-count check: this expression fires 48 times a day (2 per hour), while a real 45-minute interval fires 32 times (1440 / 45). If your metrics show 48 daily runs, you're on the cron form.
Frequently Asked Questions
Why did my job fire at 09:45 and then again at 10:00?
That's the expression working as written: */45 matches minutes 0 and 45 within each hour, and the minute field resets every hour. The 15-minute short gap appears once per hour, by construction.
What's the correct way to run something every 45 minutes in Quartz or Spring?
Skip cron for this one. Quartz: SimpleScheduleBuilder.simpleSchedule().withIntervalInMinutes(45).repeatForever() on the trigger. Spring: @Scheduled(fixedRate = 2700000), which measures 45 minutes from each run's start. Both deliver constant spacing.
Is there any single cron expression for a real 45-minute interval?
No. The pattern repeats on a 3-hour cycle (:00, :45, 1:30, 2:15, then back to :00), and a single Quartz cron expression can't couple the minute value to the hour value. Four triggers can fake it; an interval trigger does it cleanly.
*/45 * * * * in AWS EventBridge
Read this one carefully before deploying it: */45 does not deliver a steady 45-minute rhythm. The step operates inside the 0-59 minute range, matching :00 and :45 of every hour, so the gaps alternate 45 minutes, then 15, for 48 runs a day rather than the 32 a true 45-minute interval would give.
AWS EventBridge expression
cron(*/45 * * * ? *)Try it in the tester →Every 45 minutes UTC
Unix / POSIX equivalent: */45 * * * *
Field Breakdown
Using It with AWS EventBridge
If the lopsided :00/:45 pattern is acceptable — say a scrape where twice-an-hour-ish is the real requirement — the expression drops into a rule's ScheduleExpression like any other cron string. But most people typing every 45 minutes want constant spacing, and on EventBridge that is precisely what the rate syntax exists for: rate(45 minutes) fires at genuine 45-minute intervals measured from when the schedule was created, indifferent to hour boundaries. A third option, when runs must also land at predictable clock times, is accepting a divisor of 60 instead — 30-minute or hourly cron schedules keep both regularity and clock alignment.
AWS-Specific Notes
- →Cron steps reset at each field's range boundary; minute 45 plus 45 would be minute 90, which does not exist, so the sequence snaps back to :00 and produces the 45/15 alternation.
- →rate(45 minutes) gives uniform spacing but unpredictable wall-clock minutes — runs drift relative to the hour because 45 does not divide 60.
- →The expression as written fires 48 times per day, exactly twice per hour — half again more often than the 32 daily runs of a real 45-minute cycle.
Frequently Asked Questions
How do I get an actual every-45-minutes schedule on EventBridge?
Use rate(45 minutes) as the ScheduleExpression. The rate syntax measures fixed intervals from schedule creation, so consecutive runs are always 45 minutes apart — something no single cron expression can encode, because cron matches clock fields rather than elapsed time.
Is cron(*/45 * * * ? *) simply wrong, then?
It is valid and EventBridge accepts it; it just means minutes 0 and 45 of every hour. Whether that is wrong depends on intent — as a twice-hourly schedule with uneven gaps it works fine, as a 45-minute interval it does not.
Where will the runs land if I switch to rate(45 minutes)?
At creation-time-plus-multiples-of-45-minutes, so the wall-clock minute walks around the hour: a schedule enabled at 09:10 UTC fires at 09:55, 10:40, 11:25, and so on. If specific clock minutes matter, rate is the wrong tool.
*/45 * * * * in GitHub Actions
This expression does not deliver a 45-minute interval. Within the minute field's 0-59 range, */45 matches only minutes 0 and 45, so the workflow fires at :00 and :45 of every UTC hour — gaps alternating 45 minutes, then 15, for 48 runs a day instead of the 32 a true 45-minute cycle would produce.
GitHub Actions expression
*/45 * * * *Try it in the tester →Every 45 minutes UTC
Unix / POSIX equivalent: */45 * * * *
Field Breakdown
Using It with GitHub Actions
In workflow YAML it appears as on: schedule: - cron: "*/45 * * * *", and the lurching rhythm comes from cron's design: the minute pattern is re-evaluated fresh each hour, so no remainder carries across the boundary — after :45 the next match is the following :00, just 15 minutes later. If your job is a stateless poll or cache refresh, the uneven spacing is harmless. If a strict 45-minute period actually matters, no 5-field expression can express it; an external clock calling repository_dispatch every 45 minutes is the honest implementation.
GitHub-Specific Notes
- →Actual fire minutes are :00 and :45 only — the sequence runs 12:00, 12:45, 13:00, 13:45, never 13:30.
- →At 48 runs per day this produces exactly the same volume as */30, which delivers those 48 runs evenly spaced — if */45 was chosen to run less often than every half hour, it saves nothing.
- →Minute-field steps only yield uniform intervals when they divide 60 evenly (5, 10, 15, 20, 30); 45 does not, hence the asymmetric wrap.
Frequently Asked Questions
Why did my every-45-minutes workflow run again only 15 minutes after the last run?
That is the :45-to-:00 wrap. The minute field matches 0 and 45 within each hour independently, so the gap after the :45 run is always 15 minutes. The expression was never a 45-minute interval — it is a two-anchor hourly pattern.
How do I get a real 45-minute cadence on GitHub Actions?
Cron's hourly repetition makes it inexpressible in the schedule event. Either accept the 0/45 anchors, switch to an expressible interval like */30 or hourly, or run an external scheduler that hits the repository_dispatch endpoint every 45 minutes.