Unix Timestamp in Milliseconds vs Seconds

Why the same instant is written as 1700000000 in one system and 1700000000000 in another, how to tell which you are holding, and how to convert between them without landing in 1970 or the year 55,840.

Seconds or milliseconds

Convert seconds or milliseconds

Check a whole column

Mixed units in one list are fine — each line is detected on its own, and the Unit column tells you what was applied to each.

The problem in one paragraph

Unix time is defined in seconds, but a great deal of software counts in milliseconds instead, because a second is a coarse unit for measuring anything a computer does. Neither number carries a label. When a millisecond value crosses into code expecting seconds, or vice versa, nothing throws an error — you just get a date that is wrong by a factor of a thousand. That is roughly 53 years in one direction and 54,000 years in the other, which at least makes the mistake easy to spot once you know the symptom.

The two symptoms, and what they mean:

  • Your date lands in January 1970 — you passed seconds to something expecting milliseconds. Multiply by 1,000.
  • Your date lands in the year 55,840 (or any absurd far-future year) — you passed milliseconds to something expecting seconds. Divide by 1,000.

Who counts in what

Default time unit by language and platform
UnitWhere you will meet it
SecondsUnix date +%s, C time(), PHP time(), Python time.time() (float), Ruby Time#to_i, MySQL UNIX_TIMESTAMP(), JWT iat/exp/nbf, Stripe and most REST APIs, cron
MillisecondsJavaScript Date.now(), Java System.currentTimeMillis(), Kotlin, Kafka record timestamps, Elasticsearch epoch_millis, Android, .NET DateTimeOffset.ToUnixTimeMilliseconds()
MicrosecondsPostgreSQL internal storage, Python datetime resolution, some tracing formats
NanosecondsGo time.Now().UnixNano(), Prometheus and InfluxDB line protocol, Linux clock_gettime

The single most common collision is a JavaScript front end talking to a Python or PHP back end. The front end sends 13 digits, the back end calls datetime.fromtimestamp() on it, and either raises an out-of-range error or stores a date tens of thousands of years in the future.

How this tool decides

The rule is a magnitude threshold, applied to the absolute value so it works for negative timestamps too:

|value| >= 100000000000  (10^11)   →  milliseconds
|value| <  100000000000            →  seconds

Which puts the boundary here:

Behaviour around the detection threshold
InputDigitsRead asResult (UTC)
999999999910seconds2286-11-20T17:46:39Z
9999999999911seconds5138-11-16T09:46:39Z
10000000000012milliseconds1973-03-03T09:46:40Z
170000000000013milliseconds2023-11-14T22:13:20Z

The trade-off is deliberate. Below the threshold, treating a value as seconds is safe up to the year 5138 — no genuine seconds timestamp will ever be that large in any system you or your grandchildren will use. Above it, the only values misread are millisecond timestamps from between 1970 and 3 March 1973, which are vanishingly rare in practice. If you happen to be working with exactly that range, or with any value where the guess is wrong, the Seconds and Milliseconds radio buttons force the interpretation and the label under the input tells you the override is active.

Converting between units in code

Multiplying and dividing by 1,000 is trivial; the things worth getting right are rounding and integer width.

// JavaScript
const seconds = Math.floor(Date.now() / 1000);   // ms -> s, floor not round
const millis  = seconds * 1000;                  // s -> ms

# Python
import time
seconds = int(time.time())                       # already seconds
millis  = int(time.time() * 1000)

// Java
long millis  = System.currentTimeMillis();
long seconds = millis / 1000L;                   // integer division floors

// Go
now     := time.Now()
seconds := now.Unix()
millis  := now.UnixMilli()

-- PostgreSQL
SELECT EXTRACT(EPOCH FROM now())::bigint;        -- seconds
SELECT (EXTRACT(EPOCH FROM now()) * 1000)::bigint;

Two traps. First, use floor rather than round when going from milliseconds to seconds: rounding can push a timestamp into the next second and break exact-match comparisons. Note that floor and integer division diverge for negative values in some languages — Python’s // floors, C and Java integer division truncates toward zero, so -1500 / 1000 is -2 in Python and -1 in Java. For pre-1970 timestamps that one-second difference is a real bug.

Second, a millisecond timestamp needs 64 bits. It exceeded the signed 32-bit maximum back in 1970 plus 25 days, so never store one in an INT column — use BIGINT.

Questions

How many digits should a current timestamp have?

Ten in seconds, thirteen in milliseconds, sixteen in microseconds, nineteen in nanoseconds. Seconds timestamps stayed at ten digits from September 2001 and will until November 2286, so digit-counting is a reliable heuristic for any contemporary date.

Is a millisecond timestamp affected by the year 2038 problem?

Not in the same way, because nobody stores milliseconds in a 32-bit integer — it would have overflowed in January 1970. Millisecond timestamps are always 64-bit, and a signed 64-bit millisecond counter runs to the year 292,278,994. The 2038 limit specifically concerns 32-bit time_t in seconds, which overflows at 2147483647, or 2038-01-19T03:14:07Z.

My API returns milliseconds but the docs say seconds. Which do I trust?

The data. Convert one sample value here and see which reading produces a sensible date. A 13-digit value that reads as a date in the last few years when treated as milliseconds is milliseconds, whatever the documentation claims.

How do I convert nanoseconds?

Divide by 1,000,000 to get milliseconds, or simply delete the last six digits — 1700000000000000000 becomes 1700000000000. Deleting digits truncates rather than rounds, which is almost always what you want for display purposes. Paste the shortened value above.

Can I mix seconds and milliseconds in batch mode?

Yes. Each line is detected independently while the unit control is on Auto-detect, and the Unit column in the results shows what was applied to each row. Switching to a forced unit applies that unit to every line.

Why does my millisecond value from 1971 convert wrongly?

Because it is below the 10^11 threshold and gets read as seconds. This is the one documented blind spot of magnitude-based detection. Select the Milliseconds radio button to force the correct reading — the label under the input will confirm the override.

What is the difference between epoch time and Unix time?

Nothing — epoch time, Unix time, POSIX time and Unix timestamp all name the same thing: seconds elapsed since 1970-01-01T00:00:00Z, ignoring leap seconds. "Epoch time" is slightly ambiguous in principle, since other systems define their own epochs (Windows FILETIME counts from 1601, Excel from 1900), but in everyday use it means Unix time.

Related tools

More tools on this site