Reference · Precision
Timestamp precision
Epoch counters look simple until you wire seconds, milliseconds, and sub-second fields across services. This page summarizes units, portability, and the 32-bit cliff.
Seconds vs milliseconds vs microseconds vs nanoseconds
- Seconds — POSIX
time_t, many JWTexpfields, cron. - Milliseconds — JavaScript
Date, Kafka logical timestamps, browserperformance.now()anchors. - Microseconds — MySQL
DATETIME(6), some RPC frameworks (google.protobuf.Timestampuses seconds + nanos). - Nanoseconds — Go, OpenTelemetry spans, kernel trace clocks; serialize as string or structured pair to avoid float rounding in JSON.
Language-specific precision (typical)
| Language | Primary type | Notes |
|---|---|---|
| JavaScript (ECMAScript) | Number (IEEE 64-bit) | ms typical; > 2^53 unsafe for integers |
| Python 3 | float / int / datetime | μs in datetime; time.time() platform-dependent |
| Go | time.Time | ns monotonic + wall |
| Java | java.time.Instant | ns since epoch |
| Rust | SystemTime / chrono | sub-ms OS-dependent |
| C / POSIX | time_t / timespec | often s + ns field on modern libc |
The Year 2038 problem
Signed 32-bit seconds overflow after 2147483647 (2038-01-19T03:14:07Z in many interpretations). Embedded systems, legacy file formats, and binary protocols still use 32-bit fields — migrate to 64-bit epoch seconds or fixed-point pairs with an explicit schema version.
64-bit timestamp range
64-bit signed seconds covers roughly ±292 billion years from the epoch; practically unlimited for civil time. Nanosecond fields in 64 bits require pairing with a seconds field (as in protobuf) rather than a single combined integer in JSON Number space — use strings or two columns.
# Largest signed 32-bit Unix second (illustration) echo $((2147483647)) # Prefer storing migration boundary as explicit type width in schema # created_at_s64 BIGINT -- not INT