Guide
Unix Timestamps: Seconds vs Milliseconds
Timestamp bugs often come from mixing seconds and milliseconds. This guide explains how to spot and avoid them.
This technical source review checks guide claims against current standards, official documentation, and the behavior of DevPouch tools. It is not an independent security audit.
Related tools
The Unix epoch
Unix time counts elapsed time since 1970-01-01T00:00:00Z. The Z matters: the timestamp is based on UTC, not the local timezone of the machine displaying it.
Seconds versus milliseconds
Many APIs and token claims use Unix seconds. JavaScript Date values use milliseconds. A timestamp that is off by a factor of 1000 usually points to mixing these two units.
For example, JWT exp and iat claims are commonly seconds. Date.now() returns milliseconds. Passing Date.now() directly where seconds are expected creates dates far in the future.
UTC and local display
A timestamp represents one instant. UTC display is stable for logs, APIs, and cross-team debugging. Local display is useful when you need to compare that instant with what a person saw on their clock.
Common mistakes
- Treating JavaScript milliseconds as API seconds.
- Assuming a Unix timestamp stores a timezone.
- Comparing local formatted strings instead of numeric timestamps.
- Forgetting that some systems use milliseconds for logs and seconds for auth claims.
Unit examples
| Instant | Seconds | Milliseconds |
|---|---|---|
| Unix epoch | 0 | 0 |
| 2024-01-01T00:00:00Z | 1704067200 | 1704067200000 |
| One second before epoch | -1 | -1000 |
Cross-language conversion
TypeScript: new Date(seconds * 1000).toISOString()
Python: datetime.fromtimestamp(seconds, tz=timezone.utc)
Java: Instant.ofEpochSecond(seconds)
C#: DateTimeOffset.FromUnixTimeSeconds(seconds)Recognizing the unit without guessing blindly
Current Unix seconds commonly have ten digits, while current milliseconds have thirteen. That heuristic is convenient for interactive debugging but fails for historical dates, far-future dates, and values near zero. An API contract should state the unit explicitly; a converter's automatic label is a prompt to verify, not a substitute for documentation.
The value 1704067200 represents 2024-01-01T00:00:00Z in seconds. Interpreted as milliseconds it lands in January 1970. The value 1704067200000 has the inverse problem when treated as seconds and can exceed a runtime's supported date range.
UTC instant versus local presentation
A Unix timestamp identifies an instant relative to the UTC epoch. It does not contain a named timezone. Converting that instant to local display applies timezone rules from the viewer's environment, including historical daylight-saving data. Two users can see different clock times for the same timestamp while referring to the same instant.
Store and compare instants in an explicit machine format, then localize at the presentation boundary. When testing an API, assert the ISO UTC instant and test local rendering separately so a developer laptop timezone does not change the contract test.
Boundary matrix
- Zero, one second, and one millisecond after the epoch.
- Negative seconds and milliseconds before 1970.
- Exactly before, during, and after daylight-saving transitions.
- Leap-day dates and month/year boundaries.
- Maximum and minimum dates supported by every participating runtime.
- Fractional seconds and the documented rounding or truncation rule.
References
FAQ
How can I guess whether a timestamp is seconds or milliseconds?
Current Unix seconds are 10 digits, while current Unix milliseconds are 13 digits. Validation should still rely on API documentation when possible.
Does a Unix timestamp include timezone?
No. It represents an instant since the UTC epoch; timezone only affects display.