DEVESSENTIALS

0 */4 * * * — What does this cron expression mean?

0 */4 * * * gives you six evenly spaced runs a day, which works well for jobs that need to happen during working hours on more than one continent. Like every hour step, it counts wall-clock hours from midnight. On the two days a year when clocks change, one of the gaps is 3 or 5 real hours, not 4.

In plain English

0 */4 * * *

Run the job every 4 hours, on the hour: at 00:00, 04:00, 08:00, 12:00, 16:00 and 20:00.

Frequency: 6 runs per day. cronstrue reads it as “On the hour, every 4 hours”.

Open 0 */4 * * * in the Cron Builder

Field-by-field breakdown

0

Minute

0–59

*/4

Hour

0–23

*

Day of month

1–31

*

Month

1–12

*

Day of week

0–6

  • Minute0 — only at minute 0.
  • Hour*/4 — every 4th hour starting at 0: 0, 4, 8, 12, 16, 20.
  • Day of month* — every day of the month.
  • Month* — every month.
  • Day of week* — every day of the week.

Next run times

Example: next 5 runs

Example: if it is Monday, 5 Jan 2026, 09:07 UTC, the next runs of 0 */4 * * * (UTC) are:

  1. #1Mon, 5 Jan 2026, 12:00 UTC
  2. #2Mon, 5 Jan 2026, 16:00 UTC
  3. #3Mon, 5 Jan 2026, 20:00 UTC
  4. #4Tue, 6 Jan 2026, 00:00 UTC
  5. #5Tue, 6 Jan 2026, 04:00 UTC

Live times from your current clock replace this example once the page loads. Cron uses the scheduler's timezone; most cloud servers, GitHub Actions and AWS EventBridge rules use UTC.

0 */4 * * * in Quartz, AWS, GitHub Actions, Kubernetes and systemd

Crontab (Linux / macOS)

0 */4 * * * /usr/local/bin/job.sh >> /var/log/job.log 2>&1

Standard 5-field syntax used by Vixie cron, cronie, busybox crond and most libraries (node-cron, APScheduler, robfig/cron).

Quartz (6 and 7 fields)

0 0 0/4 * * ?
0 0 0/4 * * ? *

# Spring @Scheduled
@Scheduled(cron = "0 0 */4 * * *")

Quartz also supports ranges with steps, such as 0 0 8-20/4 * * ? for 08:00, 12:00, 16:00 and 20:00 only.

AWS EventBridge

cron(0 0/4 * * ? *)

# interval alternative
rate(4 hours)

Runs at 00, 04, 08, 12, 16 and 20 UTC. Since EventBridge rules are UTC-only, there is no DST effect, which is one reason to keep interval jobs in UTC.

GitHub Actions

on:
  schedule:
    # Every 4 hours, evaluated in UTC
    - cron: '0 */4 * * *'

Runs at the same six UTC times every day. For a release or dependency-check workflow, offsetting the minute (for example 23 */4 * * *) reduces queueing delays.

Kubernetes CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: every-4-hours
spec:
  schedule: "0 */4 * * *"
  timeZone: "Etc/UTC"
  concurrencyPolicy: Forbid
  startingDeadlineSeconds: 1200
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: job
              image: alpine:3.20
              command: ["/bin/sh", "-c", "echo running"]

A 20-minute deadline gives the Job time to start after a brief controller outage without risking overlap with the next run.

systemd timer

# /etc/systemd/system/myjob.timer
[Unit]
Description=Every 4 hours

[Timer]
OnCalendar=*-*-* 00/4:00:00
Persistent=true

[Install]
WantedBy=timers.target

Explicit equivalent: *-*-* 00,04,08,12,16,20:00:00.

When to use every 4 hours

  • Syncing CRM or ERP data into a warehouse a few times per business day.
  • Checking for upstream dependency or container image updates.
  • Sending shift-change reports for teams working in 8-hour shifts (every other run).
  • Rotating logs on busy hosts where daily rotation produces files that are too large.

Common pitfalls with 0 */4 * * *

DST makes one interval 3 or 5 hours long

If the scheduler runs in a local timezone with daylight saving, the hour field means wall-clock hours. In the US, on the spring-forward night the 00:00 and 04:00 runs are only 3 real hours apart, because 02:00 to 03:00 doesn't exist. In autumn that gap is 5 hours. If you need strict 4-hour spacing, run the scheduler in UTC.

Don't forget the minute

* */4 * * * runs every minute during hours 0, 4, 8, 12, 16 and 20, which is 360 runs a day. The leading 0 is what makes it once per block.

# WRONG: 360 runs/day
* */4 * * *

# RIGHT: 6 runs/day
0 */4 * * *

Business hours only

If the job is only useful during the working day, restrict it with a range-step instead of running at midnight and 04:00 for nothing.

# 08:00, 12:00, 16:00, 20:00, Monday to Friday
0 8-20/4 * * 1-5

Related cron expressions

Need a different schedule? Paste 0 */4 * * * into the Cron Builder and edit it, browse all cron expressions, read the cron syntax guide or copy from the cron examples list.

Frequently Asked Questions

What does 0 */4 * * * mean in cron?▾

Every 4 hours on the hour. It runs at 00:00, 04:00, 08:00, 12:00, 16:00 and 20:00 every day in the scheduler's timezone, six times in total.

What is the difference between 0 */4 * * * and 0 0/4 * * *?▾

In Quartz and AWS they mean the same: every 4th hour starting at 0. In a crontab, use */4 (or 0-23/4); a step after a single number such as 0/4 is not portable across cron daemons, and some reject it.

How do I run every 4 hours but only on weekdays?▾

0 */4 * * 1-5 runs at the six 4-hour marks Monday to Friday. 0 8-20/4 * * 1-5 limits it to 08:00, 12:00, 16:00 and 20:00.