Why does your automation fire at the wrong hour?
Almost always because two systems disagree about what time it is, and nobody wrote down which one is right. Your scheduler thinks in one zone, your database stores another, and the person reading the output lives in a third. The automation is working. The agreement is missing.
I build automations from Bengaluru for clients whose customers are mostly elsewhere, so I hit this early and often. The first version of almost every workflow I write is correct in my head and wrong by five and a half hours for somebody else.
The fix is not clever code. It is a decision, made once, about where time is stored and where it is converted, and then holding that line everywhere. This article is that decision, written out.
What actually goes wrong when a workflow crosses time zones?
Four things, in my experience. A digest arrives in the middle of the night. A record lands on the wrong calendar day. A business hours check passes when the office is closed. And a deduplication window misses a duplicate because the two events look like they happened a day apart.
None of these throw an error. That is what makes them expensive. A workflow that crashes gets fixed on Tuesday. A workflow that sends a customer email at three in the morning their time keeps doing it until somebody complains, and the person who complains is usually the client rather than the customer.
So the first thing I do on any workflow that touches a schedule or a date is ask what the failure would look like if it were silently off by several hours. If the answer is nothing much, I move on. If the answer is a customer notices, I slow down and get it right.
Where should a timestamp be stored, and where should it be converted?
Store in UTC, always, with an explicit offset in the string. Convert only at the edges, where a human reads it or types it. Every layer in between should be indifferent to where anyone lives. If a timestamp changes meaning as it moves through your workflow, you have built a bug that will surface months later.
In practice this means an ISO 8601 string with a Z or a numeric offset on the end, not a friendly string like the third of October at nine. Friendly strings are for screens. The moment one gets stored in a field and read back by another step, the zone it was written in is gone, and no amount of downstream logic can recover it.
The same rule applies to the tools in between. Airtable, Google Sheets, HubSpot and a Postgres table will each have their own opinion about how to display a datetime, and those opinions are set per user or per workspace rather than per record. Display settings are not storage. Check what your tool's own documentation says about how it stores and renders datetimes before you trust what you see in a cell.
I make this explicit in the workflow itself now. The field is named with the zone in it, or the step that converts is named for the conversion it performs. Future me reads step names, not intentions, which is the same reason I care so much about naming conventions that keep an automation maintainable.
What breaks when daylight saving changes?
Any logic that assumes a fixed offset. If you hardcoded five hours behind for a US client in January, you are an hour wrong from March. Worse, you are wrong for only part of the year, so the bug appears, disappears, and reappears, and nobody connects the three incidents.
The honest answer is that you should never store an offset as a number. Store the zone name instead, the region and city form that identifies a set of rules rather than a fixed distance from UTC. Offsets change. Zones carry the rules for when they change.
There is a second failure that catches people out. On the day clocks move forward, one local hour does not exist. On the day they move back, one local hour happens twice. If your automation runs hourly and keys off local time, it will skip a run in spring and double a run in autumn. That is exactly the kind of thing that produces one mysterious duplicate a year.
India does not observe daylight saving, which means I do not get reminded of any of this by my own calendar. I have to remember it deliberately, and I put a note in the workflow where the assumption lives so the next person does not have to rediscover it.
Why is a date without a time the most dangerous field you have?
Because it looks unambiguous and is not. A date-only value has no zone, so the system that reads it has to guess, and different systems guess differently. The same signup can land on the thirtieth in one report and the first in another, and both reports will look correct to the person holding them.
This is where month end reporting quietly falls apart. A deal that closed at eleven at night on the last day of the month in one zone closed on the first of the next month in another. Nobody is lying. The two systems simply resolved the same instant onto different calendar days.
My rule is that if a date is going to be counted, summed or compared, it gets stored as a full timestamp and bucketed into days at the reporting step, using one declared zone that is written down somewhere a human can find. Which zone matters less than the fact that it is chosen once and stated plainly.
How should a scheduled automation decide what today means?
By being told, not by assuming. A scheduled run should take the zone it reports in as an explicit setting, not inherit it from whatever machine happens to execute it. If the workflow moves to a different account, a different region or a different tool, an inherited zone moves with the machine and your output shifts without warning.
This is the part people skip, because on day one the inherited value happens to be right. It stays right until a migration, a new team member in another country, or a vendor changing a default. Then it is wrong and nothing announces it.
The same thinking applies to when the run happens at all. A nightly job that runs at midnight somewhere is running at lunchtime somewhere else, and if two jobs both pick a comfortable local hour they can end up on top of each other. I wrote about that specific failure in how to schedule automations so they do not collide, and time zones are the reason most collisions are not obvious from the schedule.
What does working from a half hour offset teach you?
That any assumption built on whole hours is fragile. Indian Standard Time is five and a half hours ahead of UTC. Plenty of code, and plenty of spreadsheet formulas, quietly assume offsets are integers. When they are not, the error is thirty minutes, which is small enough to be dismissed and large enough to matter for anything hourly.
I have found this in more places than I expected. Rounding logic that floors to the hour. Business hours checks written as a simple greater than. Report buckets that start on the hour. Each one worked perfectly for everyone in a whole hour zone and was subtly off for me.
The lesson generalises. If your automation serves people in more than one place, the edge cases are not exotic. They are somebody's ordinary Tuesday. Building from a half hour offset just means I find them sooner than most people do.
How do you test time zone logic without waiting for March?
By making time an input rather than a fact. If the workflow reads the current time from a single step that you can override, you can feed it the spring transition, the autumn transition, a month boundary and a midnight in each zone you care about, and watch what it does. All of that takes an afternoon.
If instead every step calls for the current time independently, you cannot test any of this without changing the clock, and so nobody tests it. That single design choice is the difference between time zone handling you can verify and time zone handling you hope about.
Log the resolved values too. When a run happens, record the instant in UTC, the zone the workflow used, and the local time it resolved to. When something looks wrong three weeks later, those three values answer the question in seconds instead of an afternoon. That is the same reason I am particular about what an automation should log when it runs.
What should you do next?
Open the automation you trust least and find every place a date or a time is stored, compared or displayed. Write down which zone each one is in. If you cannot answer for even one of them, you have found the bug before it found your client, which is the whole point of the exercise.
Then make the three decisions: store in UTC, convert at the edges, and set the reporting zone explicitly rather than inheriting it. Those hold across Zapier, Make, n8n, a script you wrote yourself, or anything you replace them with next year.
If you have a workflow that keeps producing numbers nobody can reconcile, that is often what this looks like from the outside. Reach out if you want another set of eyes on it. Let's chat.
Get found, cited and the back office automated
Let's make your site the source AI engines quote and wire up the systems behind it.
Read more blogs
Let's get your website found and cited by AI
Tell me what you're working on, whether AI search is skipping your product, your back office is buried in manual work, or you need a build that does both.