Seconds or milliseconds? How to recognize and convert a Unix timestamp
What a Unix timestamp is, how to tell seconds from milliseconds by the number of digits, and how to convert it in JavaScript, Python and SQL without fuzzy dates.
By Felipe YamaokaPublished November 5, 20265 min read
A number that is really a date
APIs, databases, logs and tokens love to store time as a single number:
{ "createdAt": 1793880000, "updatedAt": 1793880000000 }Both values mean the same instant: 5 November 2026 at 12:00 UTC. The first is in seconds, the second in milliseconds. Mixing them up is one of the most common date bugs there is, and it produces results that look absurd at first sight: an order created in January 1970, or a session that expires in the year 58,815.
This guide explains what a Unix timestamp is, how to tell the units apart at a glance and how to convert safely in the languages you use every day.
What a Unix timestamp is
A Unix timestamp counts the time elapsed since the Unix epoch: 1 January 1970 at 00:00:00 UTC. Zero is that exact moment, 86400 is one day later and negative numbers are dates before 1970, so -86400 is 31 December 1969.
Two properties make it popular:
- It has no time zone. The number means the same instant in São Paulo, London and Tokyo. Time zones only appear when you turn it into a date for a person to read.
- It is easy to compare and sort. Later is bigger. The difference between two timestamps is a duration.
The original Unix definition counts seconds. Many platforms, starting with JavaScript, count milliseconds instead. Some systems go further: Python's time.time_ns() returns nanoseconds and many databases store microseconds internally. In practice, seconds and milliseconds are the two you will meet in JSON.
One detail: Unix time ignores leap seconds. Every day is treated as exactly 86,400 seconds. For almost all application code, this is exactly what you want.
Telling seconds from milliseconds
For dates near today, the number of digits gives it away:
- 10 digits, such as
1793880000: seconds. - 13 digits, such as
1793880000000: milliseconds.
The rule breaks for dates far from today, so tools use a threshold instead. The Unix Timestamp Converter on this site treats any absolute value from 100,000,000,000 (1e11) up as milliseconds and anything below as seconds. The cut is safe in both directions: 1e11 seconds would be the year 5138, and 1e11 milliseconds is March 1973, so no realistic date in seconds is that big and almost no date in milliseconds is that small.
If you are not sure, convert both ways and see which one makes sense:
1793880000read as seconds: 5 November 2026, 12:00 UTC.1793880000read as milliseconds: 21 January 1970.1793880000000read as milliseconds: 5 November 2026, 12:00 UTC.1793880000000read as seconds: the year 58,815.
A date in January 1970 almost always means seconds read as milliseconds. A date tens of thousands of years away means the opposite.
Converting in JavaScript
JavaScript's Date works in milliseconds, so seconds must be multiplied by 1000:
const seconds = 1793880000;
const date = new Date(seconds * 1000);
date.toISOString(); // "2026-11-05T12:00:00.000Z"To go the other way, divide and round down:
const nowMs = Date.now(); // milliseconds
const nowSeconds = Math.floor(nowMs / 1000);Prefer Math.floor over Math.round here. Rounding can move a timestamp half a second into the future, which is enough to make a token look "issued in the future" to a strict server.
To show the date to a person, format it in their time zone with Intl:
new Intl.DateTimeFormat("en-US", {
dateStyle: "long",
timeStyle: "short",
timeZone: "America/New_York",
}).format(new Date(1793880000 * 1000));
// "November 5, 2026 at 7:00 AM"Converting in Python
Python's datetime works in seconds, with fractions for anything smaller. Always pass a time zone, otherwise you get a "naive" date in the local time of the machine running the code:
from datetime import datetime, timezone
datetime.fromtimestamp(1793880000, tz=timezone.utc)
# datetime.datetime(2026, 11, 5, 12, 0, tzinfo=datetime.timezone.utc)
datetime.fromtimestamp(1793880000000 / 1000, tz=timezone.utc) # from millisecondsAnd back:
int(datetime(2026, 11, 5, 12, 0, tzinfo=timezone.utc).timestamp())
# 1793880000Converting in SQL
Each database has its own function, and most of them expect seconds:
-- PostgreSQL
SELECT to_timestamp(1793880000);
SELECT extract(epoch FROM now())::bigint;
-- MySQL
SELECT FROM_UNIXTIME(1793880000);
SELECT UNIX_TIMESTAMP();
-- SQLite
SELECT datetime(1793880000, 'unixepoch');If a column stores milliseconds, divide by 1000 before calling these functions. In MySQL, also remember that FROM_UNIXTIME returns the time in the session time zone, not in UTC.
The year 2038
Old systems store timestamps in seconds as a signed 32-bit integer. The largest value it can hold is 2,147,483,647, which is 19 January 2038 at 03:14:07 UTC. One second later the number overflows and wraps around to December 1901. Modern languages and databases use 64-bit numbers and are safe, but embedded devices, old file formats and INT columns in databases can still break. If you design a table today, store timestamps in a 64-bit column or use the database's own date type.
Common mistakes
- Passing seconds to
new Date()in JavaScript. The result lands in January 1970. - Using
Date.now()where an API expects seconds, such as theexpclaim of a JWT. The guide to reading a JWT shows how this makes tokens look broken. - Creating naive dates in Python.
datetime.fromtimestamp(ts)withouttzdepends on the server's local time zone. - Storing local time as if it were a timestamp. A timestamp is always UTC. Convert to local time only when showing it.
- Rounding up. Truncate milliseconds to seconds with floor, not round.
- Using 32-bit columns for dates that may go past 2038.
Summary
A Unix timestamp is the number of seconds, or milliseconds, since 1 January 1970 UTC. Ten digits usually mean seconds and thirteen mean milliseconds; when in doubt, convert both ways and pick the one that gives a plausible date. Multiply or divide by 1000 at the boundary between systems, keep everything in UTC until you show it to a person, and store timestamps in 64-bit columns.
Keep reading
Base64 is not encryption — what it is, when to use it and the URL-safe variant
How Base64 turns bytes into text, why it hides nothing, how to handle accents and emoji correctly and when you need the URL-safe alphabet.
November 5, 20265 min readTool: Base64 Encoder/Decoder
The regex that freezes the browser — catastrophic backtracking explained
Why a short regular expression can take seconds or hang a page, how to recognize nested quantifiers and how to rewrite the pattern so it stays fast.
November 5, 20266 min readTool: Regex Tester