MiniUtil field guide

Unix Timestamps: Seconds, Milliseconds, and 2038

Tell seconds from milliseconds at a glance, avoid factor-of-1000 conversion bugs, and understand what the 2038 limit does and does not affect.

Short answer: Unix time counts seconds, JavaScript counts milliseconds, and the digit count tells you which you are holding; the 2038 limit is a property of signed 32-bit storage, not of the format itself.

Two units share one name

A Unix timestamp is a count of seconds since 1970-01-01 UTC. Most languages, databases, and specifications use seconds, but JavaScript reports milliseconds, so values crossing that boundary need an explicit conversion. For dates in the current era a seconds value has ten digits and a milliseconds value has thirteen, which is usually enough to identify an unlabelled number.

  • 1750000000 is seconds and resolves to 2025-06-15T15:06:40Z.
  • 1750000000000 is milliseconds and resolves to the same instant.
  • A seconds value read as milliseconds lands in January 1970, which is the classic symptom.

Every day is exactly 86,400 seconds

POSIX defines the value so that each day accounts for exactly 86,400 seconds. A leap second therefore has no distinct representation, and Unix time is not a true count of elapsed physical seconds between two distant instants. For ordinary application work this is harmless, but it matters for precise interval measurement and for systems that smear leap seconds.

The 2038 limit belongs to the storage type

A signed 32-bit integer holding seconds runs out at 2147483647, which is 2038-01-19T03:14:07Z, after which it wraps to a negative value and reads as 1901. The format is not the problem; the width is. A 64-bit integer, or a millisecond value stored in a type wide enough to hold it, is unaffected. The risk lives in old database columns, embedded systems, and file formats rather than in modern language runtimes.

Check what the receiving system expects

JWT registered claims such as exp, nbf, and iat are NumericDate values expressed in seconds, so passing a JavaScript millisecond value produces a token that appears to expire tens of thousands of years from now. Dividing milliseconds by 1000 without truncating leaves a fractional value that some parsers reject. Decide on a unit at each boundary and convert deliberately.

Recognizing a raw value

ValueDigitsMeaning
175000000010Seconds: 2025-06-15T15:06:40Z
175000000000013Milliseconds: the same instant
214748364710The last instant a signed 32-bit seconds value can hold
A date in January 1970n/aA seconds value was interpreted as milliseconds