Cron Jobs and Timezones: The Complete Guide
Timezone issues are one of the most common sources of cron bugs. Jobs fire at the wrong time, or drift by an hour when DST changes. This guide covers the root causes and exactly how to fix them on every major platform.
Why Cron Defaults to UTC (or System Time)
Standard Linux cron runs jobs according to the system clock timezone. On a server configured to UTC (common for cloud VMs), all jobs run in UTC regardless of where you are.
Cloud-native schedulers like GitHub Actions and older Kubernetes versions go further — they always use UTC with no option to change it. This is intentional: UTC is unambiguous and never changes for DST.
The problem arises when developers write cron schedules in their local time, forgetting the server is UTC. A job written as 0 9 * * * expecting 9 AM New York time fires at 9 AM UTC (which is 4 or 5 AM in New York).
Daylight Saving Time (DST) Warning
If your server is set to a DST-observing timezone (e.g., America/New_York), your cron jobs will shift by one hour twice a year when clocks change. During the spring-forward transition, one occurrence is also skipped entirely. The safest practice for servers is to keep them in UTC and convert schedules manually or use a platform with native timezone support.
Platform-by-Platform Timezone Support
Set `TZ=` at the top of the crontab to apply to all jobs below it. You can also set it per-job inline on some systems.
TZ=America/New_York 0 9 * * * /path/script.sh
GitHub Actions cron always runs in UTC. There is no way to set a timezone. You must convert your target time to UTC manually.
on:
schedule:
- cron: '0 14 * * *' # 14:00 UTC = 9:00 AM ESTKubernetes 1.27+ added the `timeZone` field to CronJob spec. For older clusters, the schedule runs in the controller-manager's local time (usually UTC).
spec: schedule: "0 9 * * *" timeZone: "America/New_York"
EventBridge Scheduler natively supports timezones. Select your timezone when creating the schedule in the console or via API. Note: EventBridge cron uses 6 fields (adds year).
cron(0 9 * * ? *) Timezone: America/New_York
GCP Cloud Scheduler supports any IANA timezone. Set it in the UI or via `--time-zone` flag. Standard 5-field cron syntax.
schedule: "0 9 * * *" timeZone: "America/New_York"
Azure uses Windows timezone names (e.g., 'Eastern Standard Time'). Set `WEBSITE_TIME_ZONE` or `TZ` app setting. Note: Azure timer trigger uses 6-field NCRONTAB (seconds first).
// function.json "schedule": "0 0 9 * * *" // App Setting: WEBSITE_TIME_ZONE = Eastern Standard Time
Common Local Time → UTC Conversions
For platforms that require UTC (GitHub Actions), use this table to convert your intended schedule. Remember that DST offsets change seasonally.
| Local Time | UTC | Cron Expression |
|---|---|---|
| 9:00 AM ET (EST, UTC-5) | 14:00 UTC | 0 14 * * * |
| 9:00 AM ET (EDT, UTC-4) | 13:00 UTC | 0 13 * * * |
| 9:00 AM PT (PST, UTC-8) | 17:00 UTC | 0 17 * * * |
| 9:00 AM PT (PDT, UTC-7) | 16:00 UTC | 0 16 * * * |
| 9:00 AM CET (UTC+1) | 8:00 UTC | 0 8 * * * |
| 9:00 AM IST (UTC+5:30) | 3:30 UTC | 30 3 * * * |
| 9:00 AM JST (UTC+9) | 0:00 UTC | 0 0 * * * |
| Midnight ET (EST, UTC-5) | 5:00 UTC | 0 5 * * * |
Best Practices
Keep servers in UTC and convert schedule times manually. Avoids DST surprises.
Prefer `America/New_York` over `EST` — named zones handle DST automatically.
Add a comment like `# 9:00 AM ET (UTC-5)` next to each cron entry.
If timing precision matters, verify behavior around the spring-forward and fall-back dates.
Production servers in `America/New_York` will shift all cron schedules twice per year.
GCP and AWS support non-UTC timezones. Always check your scheduler's timezone setting.
Preview next run times with timezone support
Our Cron Debugger shows the next 10 run times in your chosen timezone — helpful for validating UTC conversions.