Skip to tool

Categories

Developer & SystemsZero Server Uploads6 min read2026-09-16

Convert Unix Epoch Timestamps to UTC and Local

Translate Unix epoch timestamps in seconds and milliseconds into human-readable datetime formats across all global timezones.

Try The Interactive Tool Now

Unix Timestamp Converter

100% In-browser execution. Zero server uploads, instant results, free forever.

Open Workbench

What Unix Epoch Time Counts, and What It Ignores

Unix time is the number of seconds elapsed since 00:00:00 UTC on 1 January 1970, the Unix epoch. It is the timestamp format underneath almost every log file, database created_at column, JWT exp claim and API response you will handle.

Its appeal is that it is a single integer with no timezone, no locale and no formatting ambiguity. 1737331200 means the same instant everywhere on Earth.

Two properties are less obvious and cause most of the confusion in practice.

Unix time ignores leap seconds. It is not a count of every physical second since 1970. The standard defines each day as exactly 86,400 seconds, so when a leap second is inserted, Unix time either repeats a value or is smeared across the day depending on the platform. The practical consequence: Unix time tracks UTC as displayed, not elapsed physical time, and differences across a leap second are off by one second. For interface work this never matters. For high-precision scientific timing it does, and TAI is the correct clock there.

Unix time has no timezone. A timestamp is an instant. "What time was that?" has no answer until you supply a zone. The same 1737331200 is 09:20 in Kolkata, 04:50 in London and 23:50 the previous day in Los Angeles. Storing a timezone alongside a timestamp is only necessary when you need to know where the user was, not when the event happened.

Seconds or Milliseconds: The Off-By-1000 That Reaches Production

The single most common timestamp bug is confusing the two units, and it is easy because both are integers that look plausible.

  • Unix standard, most backends, JWT claims, PostgreSQL `EXTRACT(EPOCH...)`: seconds.
  • JavaScript `Date.now()`, Java `System.currentTimeMillis()`, most JSON APIs written in those languages: milliseconds.

Passing seconds where milliseconds are expected produces a date in January 1970. Passing milliseconds where seconds are expected produces a date roughly 50,000 years in the future. Both failures are loud if you look at the output and silent if you only check that the code did not throw.

A reliable way to tell them apart by eye, valid for dates near the present:

DigitsUnitExample era
10seconds2001–2286
13milliseconds2001–2286

A 10-digit value beginning with 1 is a recent timestamp in seconds. A 13-digit value beginning with 1 is the same instant in milliseconds. In JavaScript the conversion is explicit and belongs at the boundary where data enters your system:

jsread-only
const fromSeconds = (s) => new Date(s * 1000);
const toSeconds = (d) => Math.floor(d.getTime() / 1000);

Use Math.floor, not Math.round. Rounding can push a timestamp into the following second, which breaks exact-match queries and makes exp claims expire a second late.

The Year 2038 Problem Is Still Real

A signed 32-bit integer holds a maximum value of 2,147,483,647. As a Unix timestamp that is 03:14:07 UTC on 19 January 2038. One second later it overflows to negative, and systems using 32-bit time_t interpret the result as 13 December 1901.

This is not a historical curiosity. It is live in three places today:

  1. Embedded and industrial systems with long service lives — meters, controllers, medical devices — many still built on 32-bit platforms.
  2. Databases with 32-bit timestamp columns. MySQL's TIMESTAMP type maxes out at 2038-01-19 03:14:07 UTC by design. DATETIME does not have this limit, and the difference matters when storing future dates.
  3. Anything calculating far-future dates now — a 30-year mortgage schedule, a lease expiry, a certificate validity window. These cross the boundary years before 2038 arrives.

The remedy is to use 64-bit time throughout, which pushes the limit approximately 292 billion years out. In JavaScript this is already the case: Date stores milliseconds as a double and its usable range is ±8.64 × 10^15 ms, roughly ±273,000 years. In MySQL, prefer DATETIME or BIGINT over TIMESTAMP for anything that may hold a date past 2038.

Converting Correctly, Including the Cases That Bite

Converting a timestamp for display means choosing a target zone explicitly. Relying on the runtime's local zone produces output that differs between your laptop, your CI runner and your server.

Intl.DateTimeFormat is the correct tool, and it handles daylight saving transitions and historical zone rule changes through the IANA database:

jsread-only
const fmt = new Intl.DateTimeFormat('en-GB', {
  timeZone: 'Asia/Kolkata',
  dateStyle: 'medium',
  timeStyle: 'long',
});
fmt.format(new Date(1737331200 * 1000));

Three cases deserve specific care:

Parsing a date-only string. new Date('2026-01-20') is parsed as UTC midnight under the ISO 8601 rules, while new Date('2026/01/20') is parsed as local midnight. In a zone behind UTC the first form displays as 19 January. This is the source of a great many one-day-off bugs. Be explicit: new Date(Date.UTC(2026, 0, 20)).

Daylight saving gaps. In a zone that springs forward, local times in the skipped hour do not exist. 02:30 on the transition day is not a real instant in London; converting it yields 01:30 or 03:30 depending on the library. Wall-clock arithmetic across a DST boundary is only safe with a zone-aware library.

Fixed offsets are not timezones. UTC+05:30 is an offset; Asia/Kolkata is a zone with a history of rule changes. Storing an offset loses the information needed to compute a correct local time for any other date.

Why This Belongs in the Browser

A timestamp converter needs no server. The conversion is integer arithmetic, and every current browser ships the full IANA timezone database through Intl — the same data a backend would consult.

There is a practical reason to prefer a local tool beyond speed. Timestamps in logs are rarely isolated facts. They arrive attached to request identifiers, user identifiers, error messages and internal hostnames, and pasting a log line into a remote converter sends all of it to a third party. For anyone handling production incident data, that is an avoidable disclosure.

The OpenTools Unix timestamp converter runs in the page: it detects whether a value is in seconds or milliseconds by magnitude, renders the instant in UTC and in your local zone side by side, and converts in both directions. Nothing is transmitted.

For anything you are building yourself, three rules prevent most timestamp defects:

  1. Store UTC, always. Convert to a local zone only at the moment of display.
  2. Convert units at the boundary, where external data enters, and keep one unit internally.
  3. Name the unit in the field. expiresAtSeconds or createdAtMs eliminates an entire class of bug that expiresAt invites.

Frequently Asked Questions (FAQ)

What is a Unix epoch timestamp?

A Unix epoch timestamp is the number of seconds elapsed since 00:00:00 UTC on 1 January 1970. It represents a single instant with no timezone attached, so the same value refers to the same moment everywhere. It also excludes leap seconds, because the standard defines every day as exactly 86,400 seconds.

Is my timestamp in seconds or milliseconds?

Count the digits. For dates near the present, a 10-digit value is seconds and a 13-digit value is milliseconds. Passing seconds where milliseconds are expected produces a date in January 1970, and passing milliseconds where seconds are expected produces a date tens of thousands of years in the future. JavaScript Date.now() returns milliseconds while most backends and JWT claims use seconds.

What is the year 2038 problem?

A signed 32-bit integer holds a maximum of 2,147,483,647, which as a Unix timestamp is 03:14:07 UTC on 19 January 2038. One second later it overflows to negative and is read as December 1901. It still affects embedded systems, MySQL TIMESTAMP columns which cap at that exact instant, and any calculation of far-future dates such as a 30-year mortgage schedule. Using 64-bit time or MySQL DATETIME avoids it.

Why is my date one day off when I parse it?

new Date("2026-01-20") is parsed as UTC midnight under ISO 8601 rules, while new Date("2026/01/20") is parsed as local midnight. In any timezone behind UTC the first form displays as the previous day. Construct the date explicitly with Date.UTC(2026, 0, 20) to remove the ambiguity.

Should I store timestamps with a timezone?

Store UTC and convert to a local zone only when displaying. A timestamp is an instant and needs no zone to be unambiguous. Store a zone separately only when you specifically need to know where the user was, not when the event occurred, and store an IANA zone name such as Asia/Kolkata rather than a fixed offset, since offsets lose the rule history needed for other dates.

Can I convert timestamps without sending data to a server?

Yes. The conversion is integer arithmetic and every current browser ships the full IANA timezone database through the Intl API, which is the same data a backend would use. This matters because log lines usually carry request identifiers, user identifiers and internal hostnames alongside the timestamp, and pasting one into a remote converter discloses all of it.

Related Guides & Solutions

Ready to use Unix Timestamp Converter?

Execute this workflow privately on your device right now without creating an account or paying for cloud API credits.