Skip to content

Unix Timestamp Converter: Convert Epoch Time to Date Instantly

Free Unix timestamp converter — auto-detects seconds/ms/µs/ns, converts to any timezone with BigInt precision, and covers the Year 2038 problem.

Try it now: Unix Timestamp Converter Convert epoch seconds, milliseconds, microseconds and nanoseconds to a date in any timezone and back, with BigInt precision so nanosecond values are never rounded.

What Unix Time Actually Is

Unix time — also called epoch time — is a count of seconds elapsed since 1970-01-01T00:00:00 UTC, a single moment known as the epoch. There is nothing special about that date astronomically; it was chosen because it was a convenient round point for the Unix systems that first adopted the convention in the early 1970s, and it stuck. Every mainstream operating system, database, and programming language runtime has agreed on the same reference point ever since, which is the entire reason a raw integer like 1785758400means the same instant whether it's read by a Python script, a Postgres row, or a browser running JavaScript.

The reason systems reach for a single integer instead of a formatted string like 2026-08-03T12:00:00Zcomes down to what you can do with it cheaply. Comparing two integers is one CPU instruction; comparing two date strings correctly means parsing both first, handling variable field widths, and getting timezone offsets right before the comparison even starts. Sorting a million rows by an integer column is a plain numeric sort; sorting by a formatted date string only works if every row happens to use the same format and the same zone, which is exactly the kind of assumption that breaks quietly. An epoch value also makes arithmetic trivial — "how many seconds until this token expires" is one subtraction, not a call into a date-math library.

None of that means epoch values are meant to be read by humans. They're the storage and transport format; a unix timestamp converteris the tool that sits at the boundary, turning a raw integer into a date someone can actually read, and turning a date someone picks on a calendar back into the integer a system expects. That's exactly what GenKitLab's Unix Timestamp Converter does, in both directions, entirely in your browser — nothing you paste in is ever uploaded anywhere.

The Same Number, Four Different Meanings

Here is the single most common source of bugs in anything that touches Unix time: the epoch is defined in seconds, but almost nothing in practice only ever hands you seconds. JavaScript's Date.now() returns milliseconds. Some logging pipelines emit microseconds. High-resolution tracing systems increasingly emit nanoseconds. The number itself gives no hint which one you're holding — it's just digits — and a converter that assumes "seconds" unconditionally will confidently render the wrong date.

The fix is that the magnitude of the number tells you which unit it's in, because each unit multiplies the same moment by a fixed power of ten. As of 2026, current Unix time in seconds sits around 1.78 billion — a 10-digit number — which fixes the digit count for every other unit relative to it:

UnitDigits, as of 2026Where it comes from
Seconds10The Unix time definition itself; time(), most database epoch columns
Milliseconds13JavaScript's Date.now(), Java's System.currentTimeMillis()
Microseconds16Python's time.time_ns() / 1000, some database high-precision columns
Nanoseconds19Go's time.UnixNano(), tracing and observability systems
2026-08-03T12:00:00Z, in every unit
seconds:      1785758400
milliseconds: 1785758400000
microseconds: 1785758400000000
nanoseconds:  1785758400000000000

// Same instant. Four different integers, each ten times longer than the
// last. A parser that assumes "seconds" unconditionally will render one
// of the other three as the wrong date -- confidently, with no error.

This is why a tool built to handle timestamp to date and epoch to date conversion has to detect the unit rather than assume it. A reasonable rule of thumb — count the digits, and pick the unit whose typical width they match — catches the overwhelming majority of real values:

javascript — unit detection by digit count
function detectUnit(value) {
  const digits = Math.abs(value).toString().length;
  if (digits <= 10) return "seconds";
  if (digits <= 13) return "milliseconds";
  if (digits <= 16) return "microseconds";
  return "nanoseconds"; // 17-19 digits
}

detectUnit(1785758400);      // "seconds"
detectUnit(1785758400000);   // "milliseconds"
detectUnit(1785758400000000); // "microseconds"

Get the unit wrong in either direction and the failure is dramatic, not subtle. Feed a 10-digit seconds value straight into an API that expects milliseconds, and it computes a moment about 20 days after the epoch — a date parked in January 1970, which is exactly the "why is this row dated 1970" bug that shows up whenever a seconds value leaks into a milliseconds field unconverted. Go the other way — feed a 13-digit milliseconds value into something that treats the raw integer as seconds and then multiplies by 1000 to get milliseconds — and the result overshoots the other direction entirely, landing somewhere around the year 58,564. Neither failure is a rounding error you might miss; both are obviously broken dates, if anyone happens to be looking at the output.

Floating-Point Precision: Why Nanoseconds Need BigInt

JavaScript's Number type is a 64-bit float, and it only represents every integer exactly up to Number.MAX_SAFE_INTEGER2^53 - 1, or 9,007,199,254,740,991. Past that point, some integers simply have no exact representation as a double; the runtime silently rounds to the nearest value it can represent, with no error, no warning, and no indication that anything happened at all.

What that ceiling means for each Unix time unit is worth being precise about, because it isn't the same for all four:

  • Seconds and millisecondsstay safely inside that range for a very long time — a millisecond epoch value doesn't reach Number.MAX_SAFE_INTEGER until roughly the year 287,396. Not a practical concern.
  • Microsecondshave more headroom than most people assume, but it isn't unlimited — the safe range runs out around the year 2255. Comfortable today, but not something to treat as infinite.
  • Nanoseconds are the one that actually bites, and it bites now, not decades from now: a nanosecond epoch value exceeds Number.MAX_SAFE_INTEGER for any date after roughly April 1970 — about 104 days after the epoch itself. Every nanosecond timestamp anyone generates today for a real event is already past that ceiling.

In practice, that means naive JavaScript math silently corrupts the least significant digits of any nanosecond-since-epoch value the moment it's parsed as a plain Number — which is precisely why a tool that claims nanosecond precision has to hold the raw value as a BigIntfrom the moment it's parsed, and only ever do arithmetic on it as a BigInt, never by round-tripping through Number along the way:

javascript — where Number quietly loses precision
// Number.MAX_SAFE_INTEGER = 9,007,199,254,740,991 (2^53 - 1)

const ns = 1785758400123456789;         // a nanosecond timestamp, as a plain Number
const nsPlusOne = 1785758400123456790;  // one nanosecond later
console.log(ns === nsPlusOne);          // true -- both round to the same double

const nsBig = 1785758400123456789n;         // the same value, as a BigInt
const nsBigPlusOne = 1785758400123456790n;
console.log(nsBig === nsBigPlusOne);        // false -- BigInt keeps every digit exact

This is the reason GenKitLab's timestamp converter parses and stores the raw value as a BigInt end to end. A nanosecond value pasted in comes back out exactly as entered — no digits swapped, no silent rounding — regardless of how far the date sits from the epoch.

Timezones: the Epoch Is Absolute, the Date You See Isn't

An epoch value names one specific, physical instant — the same instant everywhere on Earth, at the same moment, for everyone. There is no such thing as "1785758400 in Tokyo time" as distinct from "1785758400 in New York time": the integer itself carries no timezone, because it doesn't need one. It's a distance from a fixed point, measured in seconds, full stop.

Timezone only enters the picture the moment you renderthat instant as a human-readable date — year, month, day, hour. And that's the actual root cause behind almost every "why does this timestamp show the wrong day" report: it's never the epoch value that's wrong, it's an unstated or mismatched assumption about which timezone it was rendered into. A timestamp logged at 11:58 PM in one zone and displayed in a zone eleven or twelve hours ahead genuinely does fall on the next calendar day — that isn't a bug in the number, it's two different, both-correct answers to two different questions.

The fix isn't to declare UTC the universal default and stop worrying about it. UTC avoids the ambiguity of "whose local time," but a user-facing date — a booking's check-in day, an invoice's due date, a log line a support engineer is reading at their desk — usually needs to be rendered in aspecifictimezone that means something to whoever's reading it, and that isn't always UTC and isn't always the viewer's own browser zone either. Being explicit about which zone a timestamp renders into is the actual fix; treating any one zone as a default that makes the question disappear is how the bug keeps coming back.

javascript — one instant, three timezones
const epochSeconds = 1785758400; // 2026-08-03T12:00:00Z

new Intl.DateTimeFormat("en-US", {
  timeZone: "UTC",
  dateStyle: "full",
  timeStyle: "long",
}).format(epochSeconds * 1000);
// "Monday, August 3, 2026 at 12:00:00 PM UTC"

new Intl.DateTimeFormat("en-US", {
  timeZone: "Pacific/Kiritimati", // UTC+14, among the earliest local dates on Earth
  dateStyle: "full",
  timeStyle: "long",
}).format(epochSeconds * 1000);
// "Tuesday, August 4, 2026 at 2:00:00 AM +14"

new Intl.DateTimeFormat("en-US", {
  timeZone: "Pacific/Midway", // UTC-11, among the latest
  dateStyle: "full",
  timeStyle: "long",
}).format(epochSeconds * 1000);
// "Monday, August 3, 2026 at 1:00:00 AM -11"

One epoch integer, and the calendar date it prints as spans two different days depending purely on which zone you asked for — a 25-hour spread between the earliest and latest local dates on Earth at the exact same instant. That's why GenKitLab's converter lets you pick any IANA timezone for the rendered date, not just a toggle between UTC and whatever zone your own browser happens to be set to.

The Year 2038 Problem

Plenty of systems don't store Unix time as an arbitrary-width integer — they store it as a signed 32-bit integer, a convention baked into decades of C code, filesystem formats, and embedded firmware. A signed 32-bit integer tops out at 2,147,483,647. Counting seconds from the epoch, that ceiling is reached at exactly 2038-01-19T03:14:07 UTC.

One second later, the correct value would be 2,147,483,648— which doesn't fit. The counter overflows and wraps around to the most negative value a signed 32-bit integer can hold instead, -2,147,483,648, which renders as a date in 1901, not 2038. A system reading that wrapped value doesn't crash; it just quietly believes it's 1901, which is often worse.

the overflow, in numbers
// A signed 32-bit integer holds values from -2,147,483,648 to 2,147,483,647.
// Unix time reaches that ceiling at exactly this instant:
2147483647   // 2038-01-19T03:14:07 UTC -- the largest value that still fits

// One second later, the correct value is 2147483648 -- which doesn't fit
// in a signed 32-bit int. It wraps to the most negative representable
// value instead:
-2147483648  // renders as 1901-12-13T20:45:52 UTC on an affected system

This isn't a solved historical curiosity — it's a real, still-open issue for anything built on a 32-bit time_t: older embedded controllers, some file formats and on-disk structures that reserved exactly 32 bits for a timestamp field, and 32-bit builds of software that hasn't moved to a 64-bit time_t. Mainstream 64-bit operating systems and modern language runtimes sidestepped the problem years ago by widening the integer, but that only helps the systems that were rebuilt — legacy and embedded systems running on the old assumption don't get fixed by anyone else's upgrade.

Converting Timestamps in Code

A browser tool is the right call for a one-off value, a support ticket, or eyeballing a log line. The moment the conversion needs to run inside an application, it belongs in code — and the unit and timezone traps above apply exactly the same way there.

Python: datetime, explicitly

python
from datetime import datetime, timezone

epoch_seconds = 1785758400

# Naive -- no tzinfo attached, silently uses whatever zone the machine is set to.
naive = datetime.fromtimestamp(epoch_seconds)
print(naive)  # e.g. 2026-08-03 08:00:00, if the box happens to be set to US Eastern

# Explicit -- always name the zone, in code and in review.
utc = datetime.fromtimestamp(epoch_seconds, tz=timezone.utc)
print(utc)  # 2026-08-03 12:00:00+00:00

# fromtimestamp() always expects seconds. A milliseconds value has to be
# divided down first, or it lands on a wildly wrong date.
epoch_millis = 1785758400000
ms_as_utc = datetime.fromtimestamp(epoch_millis / 1000, tz=timezone.utc)

datetime.fromtimestamp() without a tzargument doesn't mean "no timezone" — it means the local timezone of whatever machine runs the code, silently. That's the Python equivalent of the rendering trap from the timezone section above: pass tz=timezone.utc explicitly, or whichever specific zone the output actually needs to be shown in.

SQL: to_timestamp()

sql — postgresql
-- to_timestamp() expects seconds -- the same trap as Python's fromtimestamp().
SELECT to_timestamp(1785758400);                -- 2026-08-03 12:00:00+00

-- A milliseconds column needs the same division before conversion:
SELECT to_timestamp(1785758400000 / 1000.0);

-- Render into a specific zone explicitly, rather than trusting the
-- session's timezone setting to be the one you meant:
SELECT to_timestamp(1785758400) AT TIME ZONE 'UTC';
SELECT to_timestamp(1785758400) AT TIME ZONE 'Asia/Tokyo';

AT TIME ZONE is doing the exact same job as Intl.DateTimeFormat's timeZoneoption earlier — converting one absolute instant into a specific, named zone's local calendar date, rather than leaving it to whatever the session happens to be configured with.

GenKitLab vs. Generic Epoch Converters

GenKitLabepochconverter.comunixtimestamp.com
Automatic unit detectionDetects seconds, milliseconds, microseconds, or nanoseconds from magnitude, with an explicit overrideAssumes seconds by default; other units need a manual conversion stepSeconds and milliseconds only, no microsecond or nanosecond input
Timezone renderingAny IANA timezone, not just a UTC-vs-local toggleUTC and your browser's local zoneLocal and UTC only
Precision on very large valuesRaw value held as BigInt end to end -- nanosecond digits never roundStandard JS number math; not built for nanosecond-scale inputStandard JS number math
Explains the why (unit ambiguity, precision loss, Y2038)This page, plus inline guidance in the tool itselfMinimal explanatory contentMinimal explanatory content
Sign-up requiredNoNoNo
Best fitAny unit, any timezone, and values large enough that float rounding would matterA quick default lookup in seconds or millisecondsA quick default lookup in seconds or milliseconds

Both named alternatives are genuinely useful for the common case — a seconds or milliseconds value, rendered in UTC or your own local zone. Where they run out of road is exactly where the harder bugs live: a microsecond or nanosecond value from a tracing system, a date that needs to render in a timezone that isn't yours, or a value large enough that ordinary floating-point math would quietly round it. GenKitLab's Unix Timestamp Converter runs entirely client-side and handles all three, with nothing you paste in ever transmitted anywhere.

Explore More Developer Tools

Timestamps show up constantly alongside a handful of other everyday conversions:

  • UUID Generator — UUID v7 embeds a 48-bit Unix millisecond timestamp directly in the identifier itself; see the UUID guide for how that embedded timestamp is laid out and decoded.
  • JWT Decoder — a JWT's iat and exp claims are Unix timestamps in seconds; decoding a token means running exactly this same epoch-to-date conversion on two of its fields.
  • Cron Expression Parser — once a schedule's next run time is computed, it's the same rendering question as any other timestamp: which timezone is that next run actually in?

See the full Utilities category for the rest of the everyday conversions developers reach for constantly.

Frequently asked questions

What is a Unix timestamp?

A count of seconds elapsed since 1970-01-01T00:00:00 UTC, a fixed reference point called the epoch. It's an arbitrary but universally-adopted starting line, which is why the same integer means the same instant across every operating system, database, and programming language that uses it.

How do I know if a timestamp is in seconds or milliseconds?

Count the digits. As of 2026, a 10-digit number is seconds, a 13-digit number is milliseconds (JavaScript's Date.now() convention), 16 digits is microseconds, and 19 digits is nanoseconds. A converter should detect the unit from that magnitude rather than assume seconds — assuming wrong renders a date that's either stuck in early 1970 or tens of thousands of years in the future.

Why does my timestamp show the wrong day or hour?

The epoch value itself is timezone-free -- it names one absolute instant. The wrong-looking date almost always comes from rendering that instant into an unintended or mismatched timezone, not from a bad number. The fix is to be explicit about which timezone you're rendering into, rather than assuming UTC or your browser's local zone is automatically the right default.

What is the Year 2038 problem?

Systems that store Unix time in a signed 32-bit integer overflow at exactly 2038-01-19T03:14:07 UTC, the largest value that fits. The next second wraps to the most negative representable value, which renders as a date in 1901 instead of 2038. It's a real, ongoing issue for 32-bit embedded systems and legacy time_t implementations, not a solved historical footnote.

Why does JavaScript lose precision on large timestamps?

JavaScript's Number type is a 64-bit float that only represents every integer exactly up to Number.MAX_SAFE_INTEGER (2^53 - 1, or 9,007,199,254,740,991). A nanosecond-since-epoch value exceeds that ceiling for any date after roughly April 1970, so parsing one as a plain Number silently rounds the least significant digits. Using BigInt for the raw value avoids that silent precision loss.

Is UTC always the safe default for displaying a timestamp?

UTC avoids the ambiguity of whose local time you mean, but it isn't a universal default that makes the timezone question disappear -- a user-facing date usually needs to render in a specific zone that means something to the person reading it, which isn't always UTC. Being explicit about which zone you're rendering into is the actual fix, not picking one zone and treating it as neutral.

How do I convert a Unix timestamp to a date in Python or SQL?

Python: datetime.fromtimestamp(seconds, tz=timezone.utc), always passing an explicit tz -- omitting it silently uses the machine's local zone. PostgreSQL: to_timestamp(seconds), then AT TIME ZONE 'Zone/Name' to render it into a specific zone explicitly. Both functions expect seconds, so a milliseconds value needs to be divided by 1000 first.

Does GenKitLab's timestamp converter run entirely in the browser?

Yes. Parsing, unit detection, BigInt arithmetic, and timezone rendering all happen client-side in JavaScript -- nothing you paste into the converter is uploaded or logged anywhere.

Last updated