Unix Timestamp Guide: Seconds, Milliseconds, and Time Zones
Avoid common date bugs when moving between logs, APIs, and user-facing timestamps.
Why timestamp bugs are so common
Unix timestamps look simple because they are just numbers, but they hide three separate problems that often get mixed together: the unit, the time zone, and the human display format. A bug in any one of those layers can make a system look hours, days, or even decades off.
Most production timestamp failures are not advanced calendar math issues. They are basic contract mistakes such as seconds vs milliseconds, UTC vs local time, or undocumented assumptions between backend and frontend code.
Seconds vs milliseconds: the first check to make
As a rule of thumb, 10-digit Unix timestamps usually represent seconds, while 13-digit timestamps usually represent milliseconds. Passing one where the other is expected is one of the fastest ways to create impossible-looking dates.
| Value | Likely unit | Typical meaning |
|---|---|---|
| 1717333200 | seconds | Normal Unix timestamp from logs or APIs |
| 1717333200000 | milliseconds | JavaScript Date.now()-style timestamp |
| 1717333 | too short / suspicious | Probably truncated or wrong source value |
Store UTC, render local
The safest operational model is simple: store and exchange canonical timestamps in UTC, then convert to local time only at the presentation layer. That keeps logs, APIs, databases, and cross-region services aligned on one source of truth.
If you mix local storage and local rendering across servers, browsers, and background jobs, daylight-saving shifts and regional differences quickly turn into confusing off-by-one-hour bugs that are hard to reproduce.
Common timestamp failure modes
Dates appear far in the future or are rejected as invalid.
Dates appear around 1970 or otherwise wildly incorrect.
Displayed dates shift by the viewer or server offset.
Analysts and support teams interpret the same value differently.
API contract rule: document the unit explicitly
Never force consumers to guess. If an API returns a number timestamp, the schema or docs should say whether it is seconds or milliseconds. Better yet, show an example value and label it clearly.
The same goes for imports, exports, and webhooks. Ambiguity at the contract layer is much more expensive than adding one sentence to the documentation.
A quick debugging checklist
- Count the digits first.
- Check whether the source system documents seconds or milliseconds.
- Verify whether the timestamp is intended to represent UTC or local wall-clock time.
- Compare raw numeric value and rendered display side by side before blaming business logic.
- Test with a known reference date so you can see exactly where the conversion drift begins.
The recurring trap: an instant is not the same as a schedule
A Unix timestamp represents a precise instant. It does not, by itself, explain business intent such as “run this every day at 9:00 AM in Rome” or “charge at local midnight.” Those are scheduling rules layered on top of time, not raw timestamps.
Teams run into trouble when they collapse those ideas together. The stored timestamp may be perfectly correct while the scheduling model is wrong for daylight saving changes, locale expectations, or tenant-specific time zones. Knowing that distinction saves a lot of false debugging.
Real-world places timestamp bugs show up
A test event appears expired because the replay service expects seconds while your app sends milliseconds.
One dashboard labels times as local while the export silently emits UTC values.
The browser renders local time correctly, but the API rounded or serialized the wrong unit before it arrived.
Old rows are interpreted with a legacy timezone assumption that no longer matches the current application contract.
A reliable documentation pattern
If you publish timestamps in an API or export format, document three things together: the unit, the timezone assumption, and one concrete example. For example: “created_at is a Unix timestamp in milliseconds, expressed in UTC, for example 1717333200000.”
That single sentence prevents a surprising number of bugs because consumers no longer have to reverse-engineer meaning from the value itself. Clear timestamp contracts are cheap to write and expensive to skip.