CronVibe logo CronVibe Cron Expression Studio
--:--:--

Cron At :15 and :45: 15,45 * * * *

Every hour, at minutes 15, 45. On the days it matches that means 48 runs per day, or roughly 17,520 a year. Below are the field-by-field reading, the exact minutes it lands on, and ready-to-paste blocks for crontab, Kubernetes and GitHub Actions.

Fires per run day482 min × 24 h
Matching days / year365non-leap reference year
Fires per year17,520about 336 per week

The five fields, one at a time

Cron reads left to right, from the finest unit to the coarsest. This expression fills them like so:

FieldTokenWhat it means
Minute15,4515, 45
Hour*every hour of the day
Day of month*every day of the month
Month*every month of the year
Day of week*every day of the week

The exact minutes it fires

Because the minute field resolves to 2 specific values, each hour has 2 trigger points: :15, :45.

Everything in this schedule is anchored to the top of the hour. If the box also runs other jobs at :00, shift this one with a range like 2-59/5 instead of */5 — same cadence, no thundering herd.

Paste it in

crontab -e
15,45 * * * *  /usr/bin/env bash /opt/jobs/twice-hourly-at-15-and-45.sh >> /var/log/twice-hourly-at-15-and-45.log 2>&1
Kubernetes CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
  name: twice-hourly-at-15-and-45
spec:
  schedule: "15,45 * * * *"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
            - name: twice-hourly-at-15-and-45
              image: alpine:3.20
              command: ["/bin/sh", "-c", "echo running twice-hourly-at-15-and-45"]
GitHub Actions
on:
  schedule:
    - cron: '15,45 * * * *'
jobs:
  run:
    runs-on: ubuntu-latest
    steps:
      - run: echo "running twice-hourly-at-15-and-45"

Before you ship it

  • Absolute paths only. Cron does not read your shell profile, so relative commands and $PATH lookups fail silently.
  • Stars mean "every value", not "ignore the field". A * still participates in matching; it just matches everything.
  • Overlap protection. A run that takes longer than the gap will stack. Add flock -n for shell jobs, or concurrencyPolicy: Forbid in Kubernetes.
  • Log something. Cron mails output to a mailbox nobody reads; redirect to a file and rotate it.

Frequently asked

What is the cron expression for at :15 and :45?
It is 15,45 * * * *. The engine reads it as: Every hour, at minutes 15, 45. On a day the schedule matches, it fires 48 times, and across a calendar year it fires about 17,520 times.

How many times a day does at :15 and :45 run?
On the days it is allowed to run, 48 times: 2 trigger points per hour across 24 hours of the day. Because the schedule matches 365 days in a non-leap year, the yearly total is 17,520.

Why does the job still fail with 15,45 * * * * in crontab?
Almost always the environment, not the schedule. Cron runs with a near-empty PATH and no shell profile, so node, python3 or docker resolve to nothing. Use absolute paths, and redirect both streams (>> /var/log/job.log 2>&1) so a silent failure leaves a trace.

Does at :15 and :45 still fire during a daylight-saving change?
Yes, with a caveat. When clocks spring forward the skipped wall-clock times simply do not occur that day, and when they fall back an hourly job can run twice. For jobs where a double run is harmful, guard the body with a lock file or an idempotency key rather than relying on cron to fire exactly once.

Other schedules in the library