DEVESSENTIALS

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

0 0 * * * is the canonical daily cron job and is exactly what the @daily and @midnight shortcuts expand to. Midnight is a natural boundary for “close yesterday, open today” work such as report generation or partition rotation. It is also the most crowded minute on any shared system, and the minute where date logic is most likely to be off by one.

In plain English

0 0 * * *

Run the job once a day at exactly 00:00, the start of each day, in the scheduler's timezone.

Frequency: 1 run per day. cronstrue reads it as “At 00:00”.

Open 0 0 * * * in the Cron Builder

Field-by-field breakdown

0

Minute

0–59

0

Hour

0–23

*

Day of month

1–31

*

Month

1–12

*

Day of week

0–6

  • Minute0 — at minute 0.
  • Hour0 — at hour 0, which is midnight on the 24-hour clock.
  • 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 0 * * * (UTC) are:

  1. #1Tue, 6 Jan 2026, 00:00 UTC
  2. #2Wed, 7 Jan 2026, 00:00 UTC
  3. #3Thu, 8 Jan 2026, 00:00 UTC
  4. #4Fri, 9 Jan 2026, 00:00 UTC
  5. #5Sat, 10 Jan 2026, 00: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 0 * * * in Quartz, AWS, GitHub Actions, Kubernetes and systemd

Crontab (Linux / macOS)

0 0 * * * /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 * * ?
0 0 0 * * ? *

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

Three zeros for second, minute and hour. Spring also accepts the macro @daily (or @midnight).

AWS EventBridge

cron(0 0 * * ? *)

# interval alternative
rate(1 day)

cron(0 0 * * ? *) is midnight UTC. rate(1 day) runs every 24 hours from creation time, which is usually not midnight.

GitHub Actions

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

Midnight UTC is one of the busiest moments for GitHub's scheduler. Nightly builds at 0 0 * * * are regularly delayed; a time like 37 0 * * * starts more reliably.

Kubernetes CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: every-day-at-midnight
spec:
  schedule: "0 0 * * *"
  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"]

Kubernetes also accepts @daily and @midnight in schedule. Set timeZone so “midnight” means the day boundary your business uses.

systemd timer

# /etc/systemd/system/myjob.timer
[Unit]
Description=Every day at midnight

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target

daily is shorthand for *-*-* 00:00:00. Many distros already run timers at midnight, so consider RandomizedDelaySec=15min.

When to use every day at midnight

  • Closing out daily totals and generating the previous day's report.
  • Creating tomorrow's table partition or rotating daily indexes.
  • Resetting per-day quotas, counters and rate-limit buckets.
  • Publishing scheduled content or expiring daily promotions.

Common pitfalls with 0 0 * * *

% must be escaped in crontab commands

Midnight jobs often name files by date. In a crontab line, an unescaped % is turned into a newline and everything after it is passed to the command as stdin. date +%F silently breaks. Escape each % as \%, or move the command into a script.

# WRONG: the command is cut at the first %
0 0 * * * pg_dump app > /backups/app-$(date +%F).sql

# RIGHT
0 0 * * * pg_dump app > /backups/app-$(date +\%F).sql

Which day is “today” at 00:00?

At 00:00:00 the date has already rolled over, so date returns the new day while the data you want to summarise belongs to yesterday. Compute the target date explicitly (date -d yesterday on GNU, date -v-1d on macOS) rather than assuming. If the job can start a few seconds early on another scheduler, it may even see the old date.

Midnight UTC vs your users' midnight, and DST at 00:00

On a UTC server, “end of day” for New York users is 04:00 or 05:00 UTC depending on the season. Set the scheduler's timezone instead of hard-coding an offset. Also note that a few zones, such as America/Santiago, change their clocks at midnight, so 00:00 local does not exist on the spring-forward day.

Related cron expressions

Need a different schedule? Paste 0 0 * * * 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 0 * * * mean in cron?▾

Once a day at midnight. The first 0 is minute 0, the second 0 is hour 0, and the remaining * fields allow every day, month and weekday. It is identical to the @daily and @midnight shortcuts.

Is 0 0 * * * the same as @daily?▾

Yes. In Vixie cron, cronie, Kubernetes and most libraries, @daily and @midnight both expand to 0 0 * * *. Use whichever your team finds clearer; the explicit form is more portable to tools that don't support macros, such as AWS EventBridge.

What is 0 0 * * * in AWS EventBridge and Quartz?▾

AWS EventBridge: cron(0 0 * * ? *), which is midnight UTC. Quartz: 0 0 0 * * ? (second, minute, hour, then ? for day-of-week). Spring @Scheduled: 0 0 0 * * *.