Unix timestamps: seconds versus milliseconds
How to tell 10-digit and 13-digit timestamps apart, the time zone mistake that derails incident analysis, and the Year 2038 problem.
Why time is stored as a number
A Unix timestamp counts seconds elapsed since 1 January 1970 at 00:00:00 UTC, a reference point called the epoch.
Numbers beat human-readable date strings for internal use. Strings vary in format, drag time zone and daylight saving information around with them, and make comparison and arithmetic awkward. An integer means the same thing everywhere and compares trivially.
So databases, logs, APIs, and cache expiry all tend to store timestamps, converting to a readable format only for display.
Telling seconds from milliseconds
The unit is the usual source of confusion, because platforms differ.
Seconds are used by Unix systems, PHP time(), most databases, and the JWT exp and iat claims. Milliseconds are used by JavaScript Date.now(), Java System.currentTimeMillis(), and many log collectors.
The quickest test is digit count: at present, second values have ten digits and millisecond values have thirteen, because they differ by a factor of a thousand.
Misreading the unit is obvious once you know the symptom. Reading milliseconds as seconds produces a date tens of thousands of years away, and reading seconds as milliseconds lands in early January 1970. If a date looks absurd, count the digits first.
The time zone mistake in incident analysis
A timestamp is an absolute value independent of time zones. The moment it is rendered as a readable time, however, a time zone is applied.
Servers frequently run in UTC while a developer machine runs in local time. The same timestamp then displays nine hours apart in Korea, so an incident reported at 3pm has to be traced in the 6am window of the server log.
Recording the time zone in log output, or using an ISO 8601 format such as 2024-05-08T08:00:00Z, removes most of the ambiguity. Storing everything as UTC and converting only for display eliminates the rest.
The Year 2038 problem
A timestamp held in a signed 32-bit integer maxes out at 2147483647, a value reached on 19 January 2038. Beyond that the value overflows into negative territory and is read as 1901.
Modern environments use 64-bit integers and are unaffected. Risk remains in older embedded systems, legacy applications compiled for 32-bit, and database tables whose columns were defined as 32-bit integers.
Fields holding future instants, such as expiry or scheduling times, can be affected today rather than in 2038. If a feature must store dates beyond that point, check the column type first.