A cron job that runs at the wrong hour is usually interpreting the expression in a different timezone than you expected. Print the time inside the deployed process, identify which scheduler owns the expression, then set an explicit IANA timezone or convert the schedule to UTC.
First, observe the clock that runs the job
Your laptop clock is irrelevant once the code is deployed. Log both an ISO timestamp and the timezone reported inside the process.
If the ISO time is correct but the displayed local time differs, the clock is fine. The assumption about timezone is wrong. Cloud containers commonly use UTC because it is stable and has no daylight-saving shift.
Find which layer owns the schedule
| SCHEDULER | WHERE TIMEZONE IS SET | COMMON MISTAKE |
|---|---|---|
| Linux cron | System timezone or CRON_TZ when supported | Editing the expression as if the server used laptop time |
| Platform cron | Provider setting or documented default | Assuming every provider uses local time |
| node-cron | The timezone option in code | Omitting it and inheriting the runtime default |
| Python scheduler | Trigger or scheduler configuration | Using a naive datetime without a zone |
| Database scheduler | Database or extension configuration | Comparing UTC rows with local calendar dates |
Do not fix the wrong layer. Changing the container timezone will not alter a platform scheduler that runs outside the container. Editing a platform cron will not change node-cron running inside your app.
Pin business time in code
For a report that must run at 9:00 AM in Bangkok, state that timezone next to the expression. node-cron v4 accepts an IANA timezone and can prevent overlapping runs.
Use names such as Asia/Bangkok or America/New_York, not fixed abbreviations such as EST. An IANA zone carries the historical and daylight-saving rules. A numeric offset does not.
Choose what should happen at daylight-saving changes
| REQUIREMENT | SAFER SCHEDULE |
|---|---|
| Run every fixed elapsed interval | Use UTC or an interval timer |
| Run at a local business hour | Use an IANA timezone |
| Run once per local calendar day | Store the local date already processed |
| Run during the clock-change window | Make the job safe to skip or repeat |
When a clock moves forward, some local times do not exist. When it moves backward, some occur twice. Scheduler behavior varies, so a money-moving or notification job should be idempotent: record a business key such as report:2026-08-19 and refuse to process it twice.
If the hour is right but the date is wrong
The scheduler may be correct while the query calculates "today" in UTC. A job that fires at 00:15 Bangkok time still runs on the previous UTC date. Pass an explicit business date and timezone into the job instead of deriving both from the server clock halfway through the task.
How this behaves on Spocket
Spocket cron workloads are always-on processes, and UTC is the default unless your code sets another timezone. The schedule lives in your repository rather than a separate dashboard field. A restart brings the scheduler back, but a missed run is not replayed automatically.
Use /run/cron for the hosting path and /documentation/logs-and-status to inspect actual run timestamps. If your task can exceed its interval, add overlap protection before deploying it.