Blog · Deep dive

    Deep Dive12 min read·Unix Calculator Editorial Team·May 1, 2026

    Complete Guide to Unix Timestamp Precision in 2026

    Quick answer: Unix timestamps are stored as integers counting seconds since January 1, 1970 UTC. Most modern systems use 64-bit integers (often with separate nanosecond fields), but JavaScript's Date object is limited to millisecond precision. To avoid precision loss: store instants as 64-bit integers or fixed-width decimals, never as binary floats; name fields with explicit units (*_ms, *_s); and document whether leap seconds are modeled.

    What Is Unix Timestamp Precision?

    "Precision" here means how finely an instant can be represented without rounding. At the storage layer you will see epoch seconds (roughly ten digits right now), milliseconds (thirteen digits), microseconds (sixteen digits), or nanoseconds (nineteen digits) past the same origin. The trap is not the digit count — it is silent conversion between those layers: JSON numbers are IEEE doubles, which cannot represent every 64-bit integer; ORMs may coerce database TIMESTAMP to floats; and mobile SDKs sometimes truncate to seconds for battery. Your API contract should specify both the type and the unit.

    POSIX time itself counts seconds while excluding leap seconds from the usual integer timeline, so two different UTC human strings can map to the same time_t on some systems. For observability data and finance you often need TAI-traceable policies — but for most REST and mobile apps, documenting "UTC epoch milliseconds" and sticking to it beats theoretical purity that your clients cannot implement consistently.

    FormatDigitsExampleTypical default
    Seconds101733569200Python time.time(), C time(), Redis INCR TTL
    Milliseconds131733569200000JavaScript Date.now(), Kafka logAppendTimeMs
    Microseconds161733569200000000PostgreSQL TIMESTAMPTZ, Python fromtimestamp
    Nanoseconds191733569200000000000Go time.Now().UnixNano(), Java Instant

    The JavaScript Precision Problem

    Date.now() returns milliseconds as a double. For current epochs that fits integer semantics, but the real limit is Number.MAX_SAFE_INTEGER (253−1). Anything that multiplies microseconds into a single JS number will silently lose bits. If you ingest high-resolution metrics from the browser, ship them as strings or BigInt with explicit units, not as naked number.

    // JavaScript is limited to millisecond Date resolution
    const ts = Date.now(); // e.g. 1733569200123 (ms)
    const tsSeconds = Math.floor(ts / 1000); // 1733569200
    
    // WRONG — IEEE float cannot hold every µs exactly at scale
    const bad = parseFloat('1733569200.123456');
    
    // RIGHT — keep wide integers as BigInt (microseconds example)
    const good = BigInt('1733569200123456');

    Precision Loss in Database Storage

    Databases lie in the marketing brochure. MySQL TIMESTAMP has different range and behavior than DATETIME(6). PostgreSQL TIMESTAMPTZ stores microseconds; forcing that through a 32-bit Unix column in an ORM mapper drops resolution. Always align ORM field types with migration files — a classic bug is dev environment using 64-bit epoch BIGINT while staging still has INTEGER.

    -- PostgreSQL: TIMESTAMPTZ stores microsecond resolution
    SELECT EXTRACT(EPOCH FROM NOW()); -- 1733569200.123456
    
    -- MySQL: TIMESTAMP has timezone quirks; DATETIME(6) keeps fractional seconds
    SELECT UNIX_TIMESTAMP(NOW(6)); -- 1733569200.123456
    
    -- Anti-pattern: INTEGER epoch seconds for trading audit where you need µs
    -- Prefer BIGINT for milliseconds, or NUMERIC(20,6) when SQL math must be exact

    The Y2038 Problem

    Signed 32-bit time_t maxes at 2,147,483,647 — 2038-01-19 03:14:07 UTC in the usual encoding. Legacy embedded devices, old file formats, and forgotten PHP extensions still compile with 32-bit fields. After overflow, times wrap to 1901-style representations or error codes depending on libc. The fix is boring and expensive: widen to 64-bit seconds (good for billions of years) or use native temporal types that already migrated.

    import struct
    # 32-bit signed max
    max_32bit = 2**31 - 1  # 2147483647
    print(max_32bit)
    
    import sys
    print(sys.maxsize)  # 9223372036854775807 on 64-bit CPython — not the same as time_t, but illustrates headroom

    Best Practices for Timestamp Precision

    1. Prefer integers or DECIMAL over float for stored instants.
    2. Agree on precision at ingress (API gateway) and reject ambiguous payloads.
    3. Store UTC; render with IANA zones using well-tested libraries.
    4. Use database-native temporal types when you need DST-safe civil times.
    5. Publish OpenAPI/Proto field comments that state units explicitly.

    Key takeaways

    • JavaScript caps practical Date resolution at milliseconds; large integers need BigInt or strings.
    • JSON numbers are floats — never rely on them for nanosecond audit trails.
    • MySQL vs Postgres fractional-second behavior differs; verify with EXTRACT(EPOCH).
    • Y2038 is still shipping in firmware; audit any 32-bit epoch column.
    • Name fields with units and version your schema when changing precision.

    Written by Unix Calculator Editorial Team — Senior Unix/Linux Engineers. Last verified May 2026.

    Cross-check values with the timestamp converter before migrating columns.

    Get the Unix Timestamp Cheatsheet

    One email. Instant cheatsheet. No drip sequence.

    Advertisement