DEVESSENTIALS

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

0 4 * * * is the go-to “quiet hours” schedule for nightly maintenance: late enough that midnight jobs have finished, early enough to be done before a European or US morning. The catch is that 04:00 is only quiet in one timezone. On a UTC server it is midnight in New York during summer time and 9 PM the previous evening in California.

In plain English

0 4 * * *

Run the job once a day at exactly 04:00 (4:00 AM) in the scheduler's timezone.

Frequency: 1 run per day, about 365 per year. cronstrue reads it as “At 04:00”.

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 — at minute 0, the top of the hour.
  • Hour4 — at hour 4 (4 AM on a 24-hour clock). Only this one hour matches.
  • Day of month* — every day of the month.
  • Month* — every month.
  • Day of week* — every day of the week, weekends included.

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. #1Tue, 6 Jan 2026, 04:00 UTC
  2. #2Wed, 7 Jan 2026, 04:00 UTC
  3. #3Thu, 8 Jan 2026, 04:00 UTC
  4. #4Fri, 9 Jan 2026, 04:00 UTC
  5. #5Sat, 10 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 4 * * ?
0 0 4 * * ? *

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

Seconds = 0, minutes = 0, hours = 4. Spring also lets you add zone = "Europe/Madrid" to @Scheduled so 4 AM means local time instead of the JVM default.

AWS EventBridge

cron(0 4 * * ? *)

EventBridge rules always run in UTC, so cron(0 4 * * ? *) is 04:00 UTC. EventBridge Scheduler accepts a timezone if you want 4 AM local time.

GitHub Actions

on:
  schedule:
    # Every day at 4:00 AM, evaluated in UTC
    - cron: '0 4 * * *'

GitHub Actions schedules are in UTC: this runs at 04:00 UTC, which is 00:00 in New York during EDT and 23:00 the previous day during EST.

Kubernetes CronJob

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

A one-hour starting deadline lets the nightly Job still run if the controller was down briefly at 04:00. Set timeZone explicitly, since without it the kube-controller-manager's timezone is used.

systemd timer

# /etc/systemd/system/myjob.timer
[Unit]
Description=Every day at 4:00 AM

[Timer]
OnCalendar=*-*-* 04:00:00
Persistent=true

[Install]
WantedBy=timers.target

Add Persistent=true so a machine that was off at 04:00 runs the job at next boot, which plain cron cannot do.

When to use every day at 4:00 am

  • Nightly database backups and VACUUM/ANALYZE after the day's writes have settled.
  • Rebuilding search indexes, sitemaps or static exports from the previous day's data.
  • Purging expired sessions, soft-deleted rows and old log files.
  • Pulling daily currency rates or analytics exports that providers publish shortly after midnight UTC.

Common pitfalls with 0 4 * * *

4 AM UTC is not 4 AM for your users

On cloud servers, containers and CI the clock is usually UTC. 0 4 * * * then fires at 06:00 in Madrid in summer, 00:00 in New York in summer and 13:00 in Tokyo. If the job must be “4 AM in our office”, set the timezone in the scheduler (CRON_TZ in cronie, timeZone in Kubernetes, zone in Spring) instead of doing the arithmetic in the expression, because the offset changes twice a year.

# cronie / Vixie cron with CRON_TZ support
CRON_TZ=Europe/Madrid
0 4 * * * /usr/local/bin/nightly.sh

You are not the only job at 4 AM

Distribution maintenance also likes the early morning. On RHEL and Fedora, anacron's daily jobs (logrotate, man-db, updatedb) start from 3 AM by default (START_HOURS_RANGE=3-22). If your backup and logrotate land at the same minute, both get slower. Check /etc/anacrontab and /etc/crontab before choosing the hour.

Missed if the machine is asleep

Classic cron never catches up. A laptop or a spot instance that is off at 04:00 simply skips that day. For jobs that must run once per day no matter what, use anacron, a systemd timer with Persistent=true, or a cloud scheduler.

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?▾

It runs once a day at 04:00. The first 0 is the minute, 4 is the hour (24-hour clock) and the three * fields allow every day of the month, every month and every weekday. The time is in the cron daemon's timezone, which is usually UTC on servers.

How do I write 0 4 * * * for AWS EventBridge?▾

Use cron(0 4 * * ? *). EventBridge needs six fields with a year at the end and a ? in either day-of-month or day-of-week. EventBridge rules use UTC, so this is 04:00 UTC; use EventBridge Scheduler with a timezone if you need local time.

Is 0 4 * * * 4 AM or 4 PM?▾

4 AM. Cron hours use a 24-hour clock from 0 to 23, so 4 PM would be 0 16 * * *. There is no AM/PM notation in cron.