Timestamp Conventions and Time Zones
Why every timestamp in a trading system needs an explicit time zone and clock convention, and how a silent UTC-vs-local mismatch turns into a wrong backtest or a bad trade.
Prerequisites: Exchange Calendars and Trading Sessions
A New York equities desk pulls a feed timestamped in Eastern time, joins it against a European futures feed timestamped in UTC, and forgets to convert one of them. Every bar looks correctly aligned — the code runs, the join succeeds, the numbers print — but the two series are actually offset by four or five hours depending on the season. A backtest built on that join will find signals that don't exist and miss ones that do, and nothing in the output will look obviously broken. This is the central danger of timestamps: a wrong one is almost never a crash, it's a plausible-looking number that's quietly false.
The fix is discipline about two separate questions for every timestamp: what time zone is it in, and what clock produced it? Time zone answers "New York time or UTC or exchange-local time?" Clock convention answers "did this come from the exchange's matching engine, the vendor's gateway, or my own machine when the message arrived?" Two systems can agree on the time zone and still disagree on the clock, because network delay separates when an event happened from when you saw it.
The standard fix is to store and process everything in UTC internally, converting to a local zone only at the very edges — displaying a chart to a person, or matching a timestamp against an exchange's published local hours. UTC has no daylight-saving transitions and no ambiguity about which offset applies on a given date, so two UTC timestamps are always directly comparable by subtraction. A timestamp stored as "9:30 AM" with no zone attached isn't really a timestamp; it's a guess, and it becomes a wrong guess twice a year when clocks change — New York shifts between UTC−5 and UTC−4 on a different calendar date than London shifts between UTC and UTC+1, so a strategy trading both markets sees the gap between their opens widen and narrow by an hour on different days each year. Code that hardcodes "market open is UTC−5" will silently misalign every session while the US is on UTC−4.
Worked example: a four-hour join bug
A researcher joins US equity ticks (stored as naive local time, no zone attached) against a European index future (stored in UTC) using the raw numeric hour. During US daylight saving, the actual gap between exchange-local and UTC is 4 hours, but the code was written assuming the winter offset of 5 hours. Every join lands one hour off. A same-minute correlation study that should show the two markets moving together during the overlap window instead spans a shifted, partially non-overlapping hour, and the reported correlation drops for no economic reason — the desk investigates a "regime change" that is actually a timestamp bug.
What this means in practice
Every ingestion pipeline should attach an explicit time zone to a timestamp the moment it arrives, convert to UTC immediately, and never let a naive (zone-less) timestamp persist past that first step. Logs, database columns, and API contracts should all say UTC and mean it. When a report needs local time — "the 9:30 AM open" — that conversion should happen only at the display layer, using the exchange calendar for the relevant date, because the offset itself changes with daylight saving.
Store and compare timestamps in UTC everywhere except the final display step, and always know whether a timestamp records when something happened or when your system observed it — those two questions, time zone and clock convention, are independent and both silently wrong answers look identical to a correct one.
Related concepts
Practice in interviews
Further reading
- Skiena, The Data Science Design Manual (data cleaning chapter)