Cron expression for Every day at 9pm
0 21 * * *
Runs once a day at 9pm, every day.
Next 5 runs (your local time)
These are shown in your browser’s timezone. The job itself runs in the scheduler’s timezone — often UTC — so the real run time can differ.
What people actually schedule with 0 21 * * *
- Running an end-of-evening rollup that captures the full day's activity once user traffic has largely wound down
- Sending a "plan for tomorrow" digest timed for the wind-down hour when people review the next day
- Starting a backup at 9pm so it completes before midnight-clustered jobs like logrotate compete for I/O
Use 0 21 * * * on your platform
It’s the same 5-field expression everywhere — what changes is where you put it and which timezone it runs in.
Linux / crontab
0 21 * * * /path/to/your-command
Runs in the server’s local timezone — check it with timedatectl.
Full field reference: crontab(5) man page.
GitHub Actions
on:
schedule:
- cron: "0 21 * * *"
GitHub Actions always runs scheduled jobs in UTC — there is no timezone setting, and runs can be delayed under load (official docs).
Kubernetes CronJob
spec:
schedule: "0 21 * * *"
Defaults to UTC. Set spec.timeZone (Kubernetes 1.27+)
for a specific zone — see the
CronJob docs.
Quartz / Spring @Scheduled
Quartz uses 6 fields (seconds first): 0 0 21 * * *. Watch out:
Quartz day-of-week is 1=SUN … 7=SAT (not 0–6), and day-of-month /
day-of-week use ? — double-check if your schedule touches those fields
(Quartz cron reference).
Gotchas with every day at 9pm schedules
- 9pm is 21:00.
0 21 * * *—0 9 * * *is 9am. With PM hours this high the twelve-hour error is easy to miss because both look plausible; confirm the field reads 21. - 9pm is close enough to midnight that long runs collide with the nightly job storm. A backup or rollup starting at 21:00 that runs three hours straight into
logrotate, certificate renewals, and other0 0 * * *jobs all fighting for disk I/O. Start earlier or throttle withionice -c2 -n7so it yields when midnight tasks kick in. - A 9pm "full day" rollup still misses late-timezone users. If part of your audience is hours behind the server, their evening activity lands after your 21:00 cutoff and gets counted tomorrow. Define the day boundary explicitly in the query (e.g. fixed UTC window) instead of trusting the trigger time.
Will you know if this job silently fails?
Cron jobs fail quietly — a server reboots, a path changes, or an error code is ignored — and nobody notices until the data is missing. A cron monitor (a dead-man’s-switch) alerts you when a scheduled job does not check in on time.
Monitor your cron jobs with UptimeRobot →
Disclosure: this is an affiliate link — we may earn a commission if you sign up, at no extra cost to you.
Is 0 21 * * * the right schedule?
If the rollup just needs the complete day and not a specific hour, every day at 11pm captures more late activity while still finishing before the heaviest midnight contention.
Or use the interactive cron generator & explainer, read the complete cron syntax guide, or pick another common schedule: