Skip to main content

Unix Timestamp Converter

Convert between Unix timestamps and readable dates. Detects seconds versus milliseconds, shows UTC and your local zone side by side, and flags the year 2038 limit.

Your data never leaves the browserUpdated: July 2026

Timestamp to date

The Now button fills in the current time and keeps ticking once a second until you start typing.

Enter a timestamp and its date appears here.

Date to timestamp

Enter a date and its timestamp appears here.

Key Takeaways

  • new Date(1700000000) is not 2023, it is 20 January 1970: the Date constructor takes milliseconds while most APIs send seconds.
  • Digit count tells them apart: 10 digits is seconds, 13 is milliseconds, 16 is microseconds.
  • 2147483647 seconds (19 January 2038) is the ceiling of a signed 32-bit time_t, and this tool flags any value above it.
  • A timestamp is an absolute instant and carries no timezone; the timezone belongs to how you display it.

The date that showed 1970 in production

Every order in the list is dated 20 January 1970. You check the database and the rows are correct. You check the API response and the number is correct. What is missing is one multiplication: the value arrives in seconds while new Date() expects milliseconds, so 1.7 billion milliseconds lands about twenty days after the epoch. The maddening part is that nothing throws. The date is a perfectly valid date, it is simply the wrong one.

Seconds versus milliseconds

A Unix timestamp is conventionally the number of seconds since 1 January 1970 UTC. Unix tooling, the output of EXTRACT(EPOCH ...) in Postgres, the exp and iat claims in a JWT, and APIs such as Stripe all speak seconds. JavaScript, meanwhile, produces milliseconds from Date.now() and expects milliseconds in the Date constructor. That factor of a thousand between the two worlds shows up everywhere you handle a timestamp without a date library.

javascript
const incoming = 1700000000; // the API sent seconds new Date(incoming).toISOString();// '1970-01-20T16:13:20.000Z'   <-- wrong, 20 days after the epoch new Date(incoming * 1000).toISOString();// '2023-11-14T22:13:20.000Z'   <-- correct // The other direction: Date to secondsMath.floor(Date.now() / 1000);

The practical way to tell them apart is to count digits. A present-day timestamp in seconds has 10 of them (1000000000 falls on 9 September 2001 and the band runs to 9999999999 in the year 2286), milliseconds have 13, and microseconds have 16. ClickHouse, Postgres and Chrome trace events all emit microseconds. This tool classifies your input by digit count and states which unit it read, so the guess is never left to you.

DigitsUnitExampleResolves to
10Seconds170000000014 November 2023
13Milliseconds170000000000014 November 2023
16Microseconds170000000000000014 November 2023
9 or fewerSeconds864002 January 1970
20 or moreNot guessed17000000000000000000Likely nanoseconds or an id
The bands sit three orders of magnitude apart, which makes digit count a reliable discriminator on its own.

The year 2038 problem

A signed 32-bit time_t holds at most 2147483647 seconds, which is 19 January 2038 at 03:14:07 UTC. One second later the value overflows and wraps around to 1901. JavaScript is untroubled by that ceiling because its numbers cover a far wider range; the problem appears where a value that looked fine in the browser reaches a backend. Legacy C code, embedded systems and the MySQL TIMESTAMP column (as opposed to DATETIME) are all bound by it.

Warning

This is not a distant deadline. Thirty-year mortgages, long-lived certificate expiry dates and subscription end dates already run past 2038. This tool raises a distinct warning for any value above 2147483647 seconds, because a value that renders fine in the browser can be silently mangled on its way into storage.

Timezones and storage

A timestamp is an absolute instant and carries no timezone information whatsoever. The value 1700000000 names the same moment in Istanbul as in Tokyo; only the wall clock printed on screen differs. The rule that falls out of this is short: store time as UTC and convert to the user local zone at the moment of display. Writing local time into a database means dealing with hours that repeat and hours that never happen when daylight saving shifts.

Dates before the epoch are expressed as negative timestamps, so -86400 is 31 December 1969. There is a trap here too, since some systems store time_t as unsigned and read the same bits as the year 2106. The tool reports negative values with their own warning. One more subtlety worth knowing: Unix time does not represent leap seconds, treating every day as exactly 86400 seconds, so the difference between two timestamps can be a few seconds short of the elapsed real time.

Frequently Asked Questions

Why does my date show 1970?
Almost always because a value in seconds was handed to something expecting milliseconds. 1.7 billion milliseconds is roughly twenty days after the epoch. Multiply by 1000, or paste the value here and check which unit it is read as.
Is my timestamp in seconds or milliseconds?
Count the digits: a 10-digit value is seconds and a 13-digit value is milliseconds. If you are unsure, convert it both ways and see which one produces a plausible date; the wrong reading lands either near 1970 or thousands of years out.
What exactly is the 2038 problem?
A signed 32-bit integer holds at most 2147483647 seconds, which is 19 January 2038. One second later it overflows and wraps to 1901. Sixty-four-bit systems are unaffected, but legacy C code, embedded devices and MySQL TIMESTAMP columns still live under that ceiling.
Does a timestamp carry a timezone?
It does not. A timestamp is elapsed time since the UTC epoch and names the same instant everywhere on Earth. The timezone only enters when you render that instant for a human, which is why storing UTC and converting at display time is the correct approach.
How do I get the current timestamp?
In JavaScript, Date.now() for milliseconds and Math.floor(Date.now() / 1000) for seconds. In Python, int(time.time()). In a shell, date +%s. In PostgreSQL, EXTRACT(EPOCH FROM now()). The live field on this page shows the current value as well.