Cron Timezone: Running Cron Jobs in IST on a UTC Server
Sagar Tayde · · 6 min read
Cron timezone problems look like random failures: a report arrives at 2:30 pm instead of 9 am, or a Monday job fires on Sunday night. The cause is almost always the same. Your schedule is read in UTC, and you wrote it in Indian time.
This guide shows how to convert correctly, the two traps that a simple “subtract 5:30” misses, and how
each platform and library lets you set the zone. The conversions below were generated with Python’s
zoneinfo, not worked out by hand.
On this page
- Which timezone does cron use?
- IST to UTC conversion table
- Trap 1: before 5:30 am IST, the day changes
- Trap 2: the first of the month
- Setting the timezone, platform by platform
- Setting it in code
- The schedule and the clock are not the same
- FAQ
Which timezone does cron use?
Classic Linux cron uses the server’s system timezone. Check it with:
timedatectl # or: date
Most cloud servers and containers are set to UTC. Most hosted schedulers also use UTC by default. India Standard Time is UTC plus 5 hours 30 minutes, all year: India has no daylight saving, so the offset never changes.
IST to UTC conversion table
For a job you want on Monday in India:
| You want (IST, Monday) | UTC time | Cron line on a UTC server |
|---|---|---|
| Midnight | Sunday 18:30 | 30 18 * * 0 |
| 2:00 am | Sunday 20:30 | 30 20 * * 0 |
| 5:29 am | Sunday 23:59 | 59 23 * * 0 |
| 5:30 am | Monday 00:00 | 0 0 * * 1 |
| 9:00 am | Monday 03:30 | 30 3 * * 1 |
| 9:30 am | Monday 04:00 | 0 4 * * 1 |
| Noon | Monday 06:30 | 30 6 * * 1 |
| 6:00 pm | Monday 12:30 | 30 12 * * 1 |
| 11:30 pm | Monday 18:00 | 0 18 * * 1 |
For daily jobs drop the last field: 9 am IST every day is 30 3 * * *.
Ranges convert the same way. “Every hour from 9 am to 6 pm IST” is 30 3-12 * * *. Because of the half
hour, it fires at 30 minutes past each UTC hour, which is on the hour in India.
Trap 1: before 5:30 am IST, the day changes
Look at the top of the table. Anything earlier than 5:30 am in India happens on the previous day in UTC.

So a “Monday 2 am” backup written as 30 20 * * 1 runs on Tuesday 2 am in India. The correct line is
30 20 * * 0, with Sunday as the day. Weekday ranges shift too: “2 am IST, Monday to Friday” becomes
30 20 * * 0-4.
This is the most common reason a weekly job seems to run on the wrong day.
Trap 2: the first of the month
The same shift hits dates. “2 am IST on the 1st of every month” is 20:30 UTC on the last day of the previous month.
Standard cron cannot say “last day of the month”, because months have 28 to 31 days. You have two
options: run the job at 5:30 am IST or later, so the date stays the same in UTC, or use a scheduler that
lets you set the timezone to Asia/Kolkata.
Setting the timezone, platform by platform
| Where it runs | Default zone | Can you change it? |
|---|---|---|
| Your own Linux server | The system timezone | Change the system zone, or use CRON_TZ where your cron supports it (cronie does; Ubuntu’s default cron does not) |
GitHub Actions schedule |
UTC | Its docs now describe setting an IANA timezone |
| Vercel Cron Jobs | UTC only | The newer Schedules feature adds timezones |
| Heroku Scheduler | UTC | No; adjust the time yourself |
| Render, Railway cron | UTC | Not documented as configurable |
| Voroa Cron Job or Scheduled Task | IST | It is IST already |
Sources: each platform’s documentation, checked on 7 November 2026, including the GitHub Actions events page. Platform details are in our posts on Vercel cron jobs and Heroku Scheduler.
Setting it in code
In-app schedulers take a timezone option. Use the IANA name Asia/Kolkata; avoid fixed offsets such as
+05:30 where a name is accepted.
// node-cron
cron.schedule('0 9 * * *', job, { timezone: 'Asia/Kolkata' });
# APScheduler
BlockingScheduler(timezone="Asia/Kolkata")
# Celery beat
app.conf.timezone = "Asia/Kolkata"
Without the option, node-cron and APScheduler fall back to the server’s zone, usually UTC. Celery falls back to UTC whatever the server’s zone is. Our tests of node-cron, APScheduler and Celery beat cover the other things these schedulers get wrong.
The schedule and the clock are not the same
Setting the schedule’s timezone decides when the job starts. It does not change the clock your code reads inside the job.
A job scheduled for 9 am IST can still see a UTC time from new Date().getHours() or a naive datetime.now() if the
container runs on UTC. If your job names a file by date or picks “yesterday’s” records, set the zone in
the code too, or use timezone-aware functions with Asia/Kolkata.
Cron jobs in IST on Voroa
Voroa’s Cron Jobs and Scheduled Tasks read schedules in India Standard Time, so 0 9 * * * means
9:00 am IST and 0 2 * * 1 means Monday 2 am IST, with no conversion.
The container’s own clock may still be UTC, as above, so read the date carefully inside the job. Runs are skipped while the service is stopped, and a slow run can overlap the next, so keep jobs safe to run twice. See scheduling a task on Voroa, and the background workers page for long-running processes.
FAQ
What timezone does cron use? The server’s system timezone. On most cloud servers and hosted schedulers that is UTC.
How do I convert IST to UTC for cron?
Subtract 5 hours 30 minutes. 9 am IST is 30 3 * * *. For times before 5:30 am IST, also move the day
back by one.
Why does my Monday cron job run on Tuesday? It is set for early morning IST but written with Monday in UTC. Early IST hours are the previous UTC day, so write Sunday.
Can I set a timezone in a crontab?
With cronie, yes, using CRON_TZ=Asia/Kolkata. Ubuntu’s default cron ignores it, so change the system
timezone instead.
Does India have daylight saving time? No. IST is UTC plus 5:30 all year, so a converted schedule never needs adjusting.
Which timezone name should I use for India?
Asia/Kolkata. It is the IANA name that libraries and platforms accept.
Conversions generated with Python zoneinfo on 7 November 2026. Found something out of date? Write to [email protected].