Utilido

Utilido blog

Unix timestamps: telling seconds from milliseconds in logs

Why epoch values land in 1970 or the far future, and how to sanity-check timestamps from APIs, databases, and mobile clients.

  • time
  • unix
  • debugging
  • logs
  • api

By · Published May 15, 2026 · Updated May 27, 2026 · 8 min read

A timestamp that looks wrong is often a unit mistake, not a bad clock. APIs, databases, mobile clients, and analytics pipelines mix Unix seconds, Unix milliseconds, ISO 8601 strings, and occasional microsecond values. The fastest first check is digit count: ten digits usually means seconds since 1970-01-01 UTC, while thirteen digits usually means milliseconds with three extra zeros. When you are sorting through log lines or JSON payloads, the time tools hub on Utilido groups converters and calculators that answer the same questions without mental arithmetic.

This guide walks through how to spot the mismatch, what breaks in production, and how to document values so the next engineer does not repeat the same off-by-three-zeros bug.

Digit count cheat sheet

Unix time counts from the epoch: 1970-01-01 00:00:00 UTC. Most systems you touch daily store that count as an integer.

  • 10 digits (around 1.7 billion today): usually seconds.
  • 13 digits: usually milliseconds (the same instant with three trailing zeros).
  • 16 digits: sometimes microseconds in high-resolution logs or some language runtimes.
  • ISO strings with Z or +00:00: timezone-aware text, good for copying between systems and for human-readable specs.

When a value is ambiguous, convert both interpretations and see which year is plausible. A meeting in 2026 should not decode to 1970 or 2286 unless you are working on historical archives or science fiction.

What goes wrong in practice

Feeding milliseconds into a tool or library that expects seconds pushes dates decades into the future. The reverse lands near 1970, which is the classic “my token expired in 1970” symptom.

Common places this appears:

  • JWT exp and iat claims when a library assumes the wrong unit. Pair inspection with the JWT claims checklist when authorization fails mysteriously.
  • JavaScript Date.now() returns milliseconds, while many backend APIs emit seconds.
  • PostgreSQL EXTRACT(EPOCH FROM ...) returns seconds with fractional parts; some ORMs round or scale differently.
  • Mobile analytics batches that mix SDK versions, one emitting seconds and another milliseconds in the same column.
  • Spreadsheet imports that treat long integers as scientific notation and strip precision before you notice.

Always compare UTC and local labels when debugging a server in another region. The integer is universal; the label on your laptop is not.

ISO strings vs epoch integers

JSON APIs often expose "2026-05-27T14:30:00Z" in documentation while the wire format uses 1716820200. Both represent one instant. Prefer ISO in specs and README files because the zone is visible. Prefer epoch integers in dense logs when every byte counts.

When you copy from a log into a ticket, paste the raw integer and note whether your source documentation says seconds or milliseconds. Guessing forces the reader to redo your work.

{
  "created_at": 1716393600,
  "updated_at": "2026-05-22T09:15:00Z",
  "expires_at": 1716397200000
}

In this sample, created_at is ten digits (seconds) while expires_at is thirteen digits (milliseconds). Mixed units in one payload are valid but dangerous if your parser assumes one rule for every numeric field.

Sanity-check with a converter

Paste the value from your log or JSON payload into the Unix timestamp converter. Check both interpretations if the year looks impossible. Copy the ISO line when you need a value that sorts cleanly in spreadsheets or config files.

Workflow that catches most mistakes:

  1. Copy the raw number from the log without editing digits.
  2. Convert as seconds; note the calendar year.
  3. If the year is wrong, convert as milliseconds.
  4. Write down which unit matched reality in your ticket or PR comment.

If both interpretations look plausible (rare for current dates), cross-check against another field in the same record, such as a human-readable column or a related event you know happened yesterday.

Spreadsheet and database habits

Excel and Google Sheets may display a thirteen-digit Unix value in scientific notation (1.72E+12), which invites manual edits that break the last digits. Import epoch columns as text or use a formula that divides by 1000 only when you have confirmed the unit.

In SQL, compare apples to apples:

-- If stored_at is milliseconds in a BIGINT column:
SELECT to_timestamp(stored_at / 1000.0) AT TIME ZONE 'UTC' FROM events;

Document the column unit in migration comments. Future you will not remember whether event_time was seconds on launch day and milliseconds after a mobile app release.

Duration math vs calendar dates

Epoch integers answer “what instant is this?” They do not answer “what date is 90 days from this contract start?” For deadline math across month boundaries, use the date calculator. For “what local wall clock is this instant in Berlin?” use the timezone converter after you have the correct epoch value. Remote teams often combine both steps; the timezone handoffs guide covers the meeting side once your integer is correct.

Cron, schedulers, and log correlation

Scheduled jobs express wall-clock intent (“every day at 09:00”) while logs store epoch seconds. When a job fires an hour early twice a year, the bug is often daylight saving rules in the scheduler, not the epoch integer. Still, correlating a cron firing with a log line requires matching units first.

Paste the cron expression into the cron parser to see the next run times in plain language. Then compare those instants, converted to epoch seconds, with your log timestamps. If the numbers are off by three orders of magnitude, fix the unit before you chase timezone tables.

Language and library defaults

EnvironmentCommon defaultGotcha
JavaScript Date.now()millisecondsDivide by 1000 for Unix seconds
Python time.time()seconds (float)Multiply by 1000 only when the API expects ms
Java Instant.getEpochSecond()secondstoEpochMilli() for ms
Go time.Now().Unix()secondsUnixMilli() for ms
PHP time()secondsmicrotime(true) is seconds with fraction

When integrating two services, read both OpenAPI schemas for format: int64 fields. “Integer timestamp” is not a standard by itself.

Testing and fixtures

Unit tests that hard-code 1700000000 pass for years until someone copies the fixture into an integration test against a millisecond API. Name test constants clearly: CREATED_AT_SEC vs CREATED_AT_MS. In factories, generate timestamps from one helper that documents the unit in the function name.

For end-to-end tests around token expiry, use instants a few minutes in the future in the same unit the auth middleware expects. An off-by-1000 error there produces flaky “sometimes 401” reports that waste a full sprint.

When counting digits is not enough

Some APIs use seconds with a decimal fraction in JSON (1716393600.512). Treat the integer part as seconds unless documentation says otherwise. Nanosecond timestamps appear in some tracing systems; divide appropriately before feeding them into tools built for second or millisecond precision.

If a value has fewer than ten digits, it may be a relative offset (TTL seconds) rather than an absolute epoch. Context from the field name (ttl, max_age) matters more than digit count alone.

The staging value I convert twice before opening a ticket

When a production log shows an impossible year, I paste the raw integer into the Unix timestamp tool as seconds, then immediately as milliseconds, before I read any surrounding stack trace. Half the time the fix is a one-line unit comment in the ticket; the other half is a real clock or timezone issue worth deeper digging. I learned that habit after chasing a “broken NTP” alert that was just a mobile client sending milliseconds into an endpoint documented for seconds. Naming the unit in the first comment saves the next responder from repeating both conversions.

FAQ

Why do my timestamps show 1970?

The value is almost certainly milliseconds read as seconds, or a zero/null sent where a timestamp was expected. Divide by 1000 if you have thirteen digits, or trace why the field is empty. Confirm with a converter before you assume the server clock is wrong.

How do I tell seconds from milliseconds without a tool?

Count digits: 10 ≈ seconds, 13 ≈ milliseconds for dates near the present. Then sanity-check the year. If it reads 1970 or 2286, swap the assumption and convert again.

Can the same API mix seconds and milliseconds?

Yes. Different fields may come from different services or SDK versions. Read the schema per field; do not assume one global rule. Mixed payloads are a common source of “works in staging, wrong in prod” when environments use different client versions.

Should I store seconds or milliseconds in my database?

Pick one, document it in the schema, and enforce it in migrations and API docs. Seconds are enough for most business events; milliseconds help ordering fast bursts in the same second. Consistency beats precision you never use.

Does timezone affect the Unix integer?

No. Unix time is defined in UTC. Timezone only matters when you display the instant as local wall clock text. Use a timezone converter after the epoch value is correct.

About the author

, Software engineer. Benchehida Abdelatif builds Utilido: fast browser utilities for images, PDFs, and developer workflows, with client-side processing where it matters for privacy. More about Utilido.