Unix Timestamp Converter
Nothing you enter here is stored, logged or shared.
Convert a Unix timestamp to a readable date or the other way round. The unit is detected automatically and every result shows its time zone.
How to use
- Paste a timestamp, or a date such as 2025-01-01T00:00:00.
- Pick a time zone if you need something other than your own.
- Copy whichever format you need.
Seconds, milliseconds, and everything below
Unix time is defined in seconds. JavaScript's Date is in milliseconds. Almost every date bug in a mixed codebase starts at that boundary.
The symptoms are recognisable once you know them. A seconds value handed to something expecting milliseconds lands in the small hours of 1 January 1970 - if a date in your interface is showing as 1970, this is why, essentially always. A milliseconds value read as seconds lands somewhere around the year 55,000, which is usually caught, but not always, because some display code renders it without complaint.
The unit here is inferred from digit count, which is a heuristic but a predictable and explainable one: a present-day timestamp has 10 digits in seconds, 13 in milliseconds, 16 in microseconds and 19 in nanoseconds, and the ranges do not overlap for any date anyone is realistically working with. Whatever it picks is displayed rather than assumed, and you can override it. Microsecond timestamps turn up in Postgres and in Chrome traces; nanoseconds in Go, in Prometheus and in InfluxDB. Nanosecond values exceed what a JavaScript number can hold exactly, so the conversion is done in BigInt.
What a timestamp does not contain
A Unix timestamp is an instant, and nothing else. It carries no time zone, no offset, and no calendar. Two people reading the same timestamp in Tokyo and in Lisbon are looking at the same moment and will correctly write down different wall-clock times for it, which is a feature: an instant is unambiguous in a way that a wall-clock time never is.
The consequence is that a timestamp cannot tell you what day it was locally, and converting one to a date requires choosing a zone. Every output here carries its zone for that reason, with UTC always shown alongside your local time so the two can be compared directly.
It also means a timestamp is the wrong storage for anything that is intrinsically local. A recurring 09:00 meeting, a birthday, a shop's opening hours: those are wall-clock times attached to a zone and a rule set, and storing them as instants breaks them the next time the zone's offset changes. Store the local time and the zone name, and compute the instant when you need it.
Leap seconds
Unix time is defined as though every day were exactly 86,400 seconds. The Earth does not cooperate, so leap seconds are inserted into UTC to keep it aligned with the planet's rotation - twenty-seven of them since 1972.
Because the definition has no room for them, Unix time handles a leap second by repeating a value rather than adding one. There is no Unix timestamp that means the leap second itself, and the difference between Unix time and TAI has therefore grown over the decades rather than staying fixed. Any code that computes elapsed time by subtracting two Unix timestamps is quietly off by the number of leap seconds that fell between them, which almost never matters and occasionally matters a great deal.
Large providers avoid the discontinuity by smearing: Google and AWS spread the extra second across a window either side of the event so clocks never repeat a value, at the cost of running very slightly slow for a day. Note that these smeared clocks disagree with unsmeared ones during that window, which is worth knowing if you compare timestamps across providers.
2038 and the other boundaries
A signed 32-bit integer runs out at 03:14:07 UTC on 19 January 2038, and the next second wraps to December 1901. Anything still storing Unix time in a 32-bit field - embedded systems, old file formats, database columns that were never widened - fails then. Timestamps past that point are flagged here for that reason. Sixty-four-bit storage pushes the limit far past the age of the universe and is what current systems use.
Unsigned 32-bit storage moves the boundary to 2106 instead, at the cost of not representing anything before 1970. Negative timestamps do work here: -86400 is 31 December 1969, and dates back to the start of the Gregorian calendar convert fine. JavaScript's Date has its own ceiling at 8.64e15 milliseconds either side of the epoch, roughly 273,000 years, and values beyond it are reported as out of range rather than rendered as Invalid Date.
The text formats, and which one to emit
ISO 8601 is the international standard for writing dates and times, and RFC 3339 is the tighter profile of it that internet protocols use. The RFC 3339 form - 2026-03-14T09:30:00Z, or with an offset such as +09:00 - is the one to emit from an API, because it sorts correctly as text, is unambiguous, and parses everywhere.
The Z means UTC, and an offset such as +09:00 means a fixed displacement from it. Neither is a time zone. Asia/Tokyo is a time zone: a rule set that says what the offset is on any given date, including the history of changes. An offset tells you what the clock read; only a zone name tells you where it will read that in future.
Formats to avoid in data: anything with a two-digit year, anything using slashes, and RFC 2822 dates from email headers, which carry obsolete zone abbreviations. Abbreviations are the worst of them - CST is Central Standard Time in North America, China Standard Time and Cuba Standard Time, and IST covers India, Ireland and Israel.
Storing time in a database
PostgreSQL's timestamptz is the type most applications want. Despite the name it does not store a zone: it converts the input to UTC on write and renders it in the session's zone on read, which is exactly the behaviour you want for an instant. Plain timestamp stores the wall-clock text you gave it with no zone at all, and comparing two of those from different origins produces quiet nonsense.
MySQL's DATETIME behaves like the plain type and TIMESTAMP converts to UTC but is limited to the 32-bit range ending in 2038, which is a real constraint for anything storing future dates. SQLite has no date type at all, and stores whatever convention you choose - usually ISO 8601 text or an integer.
The discipline that survives all of this is to store instants in UTC, convert at the edges, and keep the user's zone as a separate column when you need to render or schedule for them. Where a value is genuinely a local wall-clock time - a shop's opening hours, a recurring 09:00 meeting - store the local time and the zone name, and compute the instant when you need it, because the offset can change by legislation.
Clocks disagree, and some go backwards
A machine's wall clock is adjusted by NTP, which means it can jump forwards or step backwards. Measuring a duration by subtracting two wall-clock readings therefore produces negative elapsed times occasionally, and wrong ones regularly. Monotonic clocks exist for this: they only move forward and are what performance.now, clock_gettime with CLOCK_MONOTONIC, and every benchmarking library use.
Across machines the problem is worse, because two servers are never exactly synchronised. Ordering events in a distributed system by their timestamps produces sequences that contradict causality - a reply recorded before the message it answers - which is why logical clocks and sequence numbers exist.
For ordinary applications the practical advice is smaller: do not use a timestamp as a unique identifier, do not assume two events with the same timestamp happened simultaneously, and expect clock skew of at least a few seconds when comparing anything recorded on different machines. Token validation allows a skew tolerance for exactly this reason.
Showing a time to a person
A stored instant has to be rendered in the reader's zone, in their locale's format, in their language. In JavaScript the Intl.DateTimeFormat API does all three from the browser's settings, and it handles the details people get wrong by hand: month names in the right language, the right order of day and month, and twelve or twenty-four hour clocks by convention rather than preference.
Relative times - three hours ago, in two days - are friendlier for recent events and worse for old ones, since nobody can act on 431 days ago. The common pattern is relative within a day or two, then an absolute date, with the full timestamp available on hover or long press.
Two details make a visible difference. Render dates in the user's zone rather than the server's, which means sending an instant and formatting on the client rather than formatting a string server-side. And label anything ambiguous with the zone, because a meeting time without one is the single most reliable way to have somebody join an hour late.
Dates that do not exist, and other edge cases
Scheduling anything at 02:30 in a zone with daylight saving guarantees an annual incident: that time does not exist on the spring transition and happens twice on the autumn one. Jobs that must run exactly once belong in UTC, or outside the one-to-three window where transitions happen.
Calendar arithmetic has its own traps. Adding one month to 31 January has no single correct answer, and libraries differ between 28 February and 3 March. Adding 24 hours is not the same as adding a day across a transition. Leap years need the full rule - divisible by four, except centuries, except those divisible by 400 - and 29 February breaks anniversary logic every four years.
And the boundaries are real. Signed 32-bit time ends on 19 January 2038, which still matters for embedded devices and old database columns; JavaScript's Date covers roughly 273,000 years either side of 1970 and reports anything beyond as invalid. Both are worth testing for if your data includes far-future dates, as mortgage, pension and archival systems often do.
Frequently asked questions
- Is my timestamp in seconds or milliseconds?
- Count the digits. A present-day timestamp in seconds has 10 digits, in milliseconds 13, microseconds 16 and nanoseconds 19. This tool detects the unit and tells you which it used, because mixing the two is the most common date bug there is: seconds read as milliseconds land in January 1970, and milliseconds read as seconds land tens of thousands of years in the future.
- Why does the same timestamp show different clock times?
- A Unix timestamp is an absolute instant with no time zone attached. The wall-clock time it corresponds to depends entirely on where you are, which is why every output here carries its zone and UTC is always shown alongside.
- What happens in 2038?
- Systems that store Unix time in a signed 32-bit integer overflow at 2038-01-19T03:14:07Z and wrap around to 1901. This tool flags any timestamp past that point. Modern 64-bit storage is unaffected.
- Does Unix time include leap seconds?
- No. Unix time is defined as if every day were exactly 86,400 seconds, so leap seconds are skipped rather than counted. This is why it cannot represent the leap second itself, and why converting between Unix time and TAI is not a simple offset.
- Can it handle dates before 1970?
- Yes. Timestamps before the epoch are negative, so -86400 is 31 December 1969.
Last updated:
Include the steps, expected result, and actual result. Remove secrets and personal data.
