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.
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 BuilderField-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: if it is Monday, 5 Jan 2026, 09:07 UTC, the next runs of 0 4 * * * (UTC) are:
- #1Tue, 6 Jan 2026, 04:00 UTC
- #2Wed, 7 Jan 2026, 04:00 UTC
- #3Thu, 8 Jan 2026, 04:00 UTC
- #4Fri, 9 Jan 2026, 04:00 UTC
- #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>&1Standard 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.targetAdd 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.shYou 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
Every day at 2:00 AM
0 2 * * *
Every day at midnight
0 0 * * *
Every 6 hours
0 */6 * * *
Every day at 3:00 PM
0 15 * * *
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.