Cron expression for daily at midnight
The cron expression 0 0 * * * runs a job at midnight every day — exactly when the wall clock reads 00:00. Standard 5-field syntax works in Linux crontab, Kubernetes CronJob and GitHub Actions; AWS EventBridge needs the 6-field form cron(0 0 * * ? *). The single biggest gotcha: most schedulers default to UTC, not your local timezone.
Quick reference
| Platform | Expression | Default timezone |
|---|---|---|
| Unix / Linux crontab | 0 0 * * * or @daily | System local |
| Kubernetes CronJob (≥ 1.25) | 0 0 * * * + spec.timeZone | UTC if timeZone unset |
| Kubernetes CronJob (< 1.25) | 0 0 * * * | Controller’s local (usually UTC) |
| GitHub Actions | 0 0 * * * | UTC always |
| AWS EventBridge Rules | cron(0 0 * * ? *) | UTC always |
| AWS EventBridge Scheduler | cron(0 0 * * ? *) + ScheduleExpressionTimezone | UTC if timezone unset |
Which timezone is “midnight”?
This is the question that catches everyone at least once. The cron expression 0 0 * * * is a wall-clock pattern: fire when the displayed minute is 0 and the displayed hour is 0. But which clock?
Each platform has a default:
- Linux crontab uses the system’s
/etc/localtime— usually whatever you set when installing the OS. Rundateon the host to see what cron sees. - Kubernetes < 1.25 uses the kube-controller-manager pod’s local time. On managed Kubernetes (EKS, GKE, AKS) this is UTC. Self-hosted clusters can be anything.
- Kubernetes ≥ 1.25 accepts a
spec.timeZonefield. If unset, falls back to controller local. Always set it explicitly. - GitHub Actions is hardcoded UTC. There is no override; you must convert.
- AWS EventBridge Rules is hardcoded UTC. EventBridge Scheduler (newer service) accepts
ScheduleExpressionTimezone.
If you wrote 0 0 * * * thinking “midnight in my timezone” and the scheduler is on UTC, your job runs at 4 PM the previous day for someone on the US West Coast. The fix is either to convert your time to UTC, or to set the timezone explicitly.
Variations
| Schedule | Expression |
|---|---|
| Daily at 9 AM Pacific (= 17:00 UTC) | 0 17 * * * |
| Daily at 9 AM Indian Standard Time (= 03:30 UTC) | 30 3 * * * |
| Just before midnight (23:59) | 59 23 * * * |
| 5 minutes after midnight | 5 0 * * * |
| Daily at midnight in AWS | cron(0 0 * * ? *) |
| Daily at midnight Pacific in EventBridge Scheduler | cron(0 0 * * ? *) + ScheduleExpressionTimezone: 'America/Los_Angeles' |
How do I use it on each platform?
Linux crontab:
0 0 * * * /usr/local/bin/nightly-cleanup
Or with the shortcut:
@daily /usr/local/bin/nightly-cleanup
Kubernetes CronJob (1.25+ with explicit timezone):
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-cleanup
spec:
schedule: "0 0 * * *"
timeZone: "America/Los_Angeles" # critical — runs at local midnight
successfulJobsHistoryLimit: 3
jobTemplate:
spec:
template:
spec:
containers:
- name: cleanup
image: my-org/cleanup:1.0
restartPolicy: OnFailure
AWS EventBridge Scheduler (with timezone):
Type: AWS::Scheduler::Schedule
Properties:
Name: nightly-cleanup
ScheduleExpression: 'cron(0 0 * * ? *)'
ScheduleExpressionTimezone: 'America/Los_Angeles'
FlexibleTimeWindow:
Mode: 'OFF'
Target:
Arn: !GetAtt CleanupFunction.Arn
RoleArn: !GetAtt SchedulerRole.Arn
GitHub Actions (UTC only):
on:
schedule:
- cron: '0 0 * * *' # this is midnight UTC, not your local midnight
Common mistakes
Assuming 0 0 * * * runs at your midnight. It runs at the scheduler’s midnight. Always set the timezone explicitly when the platform supports it; otherwise convert to UTC.
Daylight saving silently shifts the run. A timezone like America/Los_Angeles follows DST. A job set to “midnight Pacific” is at 08:00 UTC half the year and 07:00 UTC the other half. If your downstream system expects a fixed UTC time, use UTC directly instead of a timezone.
Confusing 0 0 * * * with * * * * * or other typos. 0 0 * * * is daily; * * * * * is every minute (1440 runs/day). Easy to mis-type when copying.
For other schedules see common cron schedules, or build a custom expression with the Cron Expression Builder.
Frequently asked questions
- Does `0 0 * * *` run at local midnight or UTC midnight?
- Depends on the platform. Linux crontab uses the system's local timezone. Kubernetes CronJob before 1.25 uses the kube-controller-manager's timezone (usually UTC); 1.25+ accepts a `spec.timeZone` field. AWS EventBridge Rules are always UTC; EventBridge Scheduler accepts `ScheduleExpressionTimezone`. GitHub Actions runs in UTC, no timezone option. Always verify before relying on local midnight.
- Why did my "daily at midnight" job run at 5 PM yesterday?
- Timezone mismatch. You wrote `0 0 * * *` thinking "midnight Pacific" but the scheduler interpreted it as UTC. UTC midnight = 5 PM PST = 4 PM PDT the previous day. Either set the timezone explicitly (K8s 1.25+ `timeZone`, EventBridge Scheduler `ScheduleExpressionTimezone`) or convert to UTC: 9 AM PST = 17:00 UTC, so `0 17 * * *`.
- What is `@daily` and is it the same as `@midnight`?
- In Vixie cron, `@daily` and `@midnight` are aliases — both expand to `0 0 * * *`. They work in Linux crontab, anacron, Kubernetes CronJob, GitHub Actions. Neither works in AWS EventBridge. Stick with the explicit form when targeting AWS.
Need a different schedule?
Build cron expressions for Unix, Kubernetes and AWS — with a human-readable description and the next 5 run times.
Open the Cron Expression Builder →Related
Cron expression for every 5 minutes
The cron expression `*/5 * * * *` runs every 5 minutes in Linux crontab, Kubernetes, GitHub Actions; `cron(*/5 * * * ? *)` in AWS EventBridge.
Cron expression for every 15 minutes
The cron expression `*/15 * * * *` runs every 15 minutes — at :00, :15, :30, :45 — across Linux, Kubernetes, GitHub Actions and AWS.
Cron expression for every hour
The cron expression `0 * * * *` runs once per hour on the hour. Same syntax in Linux, Kubernetes and GitHub Actions; `cron(0 * * * ? *)` in AWS EventBridge.
Cron expression for every weekday
The cron expression `0 9 * * 1-5` runs at 9 AM Monday through Friday. AWS uses `cron(0 9 ? * MON-FRI *)` because day-of-week numbering differs.
Cron expression for the first of every month
The cron expression `0 0 1 * *` runs at midnight on the 1st of every month. AWS uses `cron(0 0 1 * ? *)`.
Cron expression for every Sunday
The cron expression `0 0 * * 0` runs every Sunday at midnight in Unix cron. AWS uses `cron(0 0 ? * 1 *)` because Sunday is `1` in AWS, not `0`.