What a Unix timestamp counts, and what it quietly ignores
A Unix timestamp is one integer: the number of seconds that have passed since 1970-01-01 00:00:00 UTC. That instant is the epoch, fixed when Unix was built at Bell Labs in the early 1970s, and the count has never been rebased since. Because it is measured from a point in UTC, the number carries no time zone, no calendar, no separators and no ambiguity. 1735689600 is the same moment in London, New York and Tokyo; only the wall clock reading differs. That is why logs, API payloads, JWT claims and database columns store the integer and leave formatting to whatever is doing the displaying.
The naive way to read one back is to guess. That fails in two directions that look nothing alike. Hand a millisecond value such as 1735689600000 to something expecting seconds and the date lands in the year 56,000, which at least announces itself. Hand a seconds value to something expecting milliseconds and you get 1970-01-20, which looks almost plausible and is easy to skim past. The second failure is subtler: a timestamp printed without saying which zone rendered it is useless for correlating two systems, and an incident timeline built from mixed local times will be wrong by whole hours.
There is one more thing the count ignores. POSIX defines every day as exactly 86,400 seconds, so the 27 leap seconds inserted into UTC since 1972 are skipped rather than counted. A Unix timestamp is therefore not a true tally of elapsed SI seconds since the epoch. It is a calendar convenience that happens to look like a stopwatch.
Which unit you have, and which output you want
Two decisions cover almost every use of this page. The Unit selector says how to read the number you pasted, and the three result rows say how you want it back. Pick the unit by counting digits:
- 10 digits: seconds. The default, and what
date +%s, PHPtime(), Gotime.Now().Unix()and JWTiatandexpclaims produce. Ten digits covers September 2001 to November 2286. - 13 digits: milliseconds. JavaScript
Date.now(), JavaSystem.currentTimeMillis(), Kotlin and most Android APIs. Switch the Unit selector before reading the result. - 16 or 19 digits: microseconds or nanoseconds. PostgreSQL internals, Go
UnixNano()and tracing systems such as OpenTelemetry. Divide by 1,000 or 1,000,000 and paste the millisecond value.
Then take the row that matches where the value is going. Local is your own device clock, labelled with the zone your browser reports, and is the one to read when you are checking whether an event lines up with something you remember. UTC is the row to quote in an incident channel or a bug report, because it is the only reading two people in different countries will agree on. ISO 8601 is the row to paste into code, a config file or a spreadsheet, since the trailing Z makes the offset explicit and every modern parser accepts it.
How to read a timestamp out of a log line
- Copy just the number. Leading labels, trailing commas and quote marks all make it unreadable, and a fractional value such as
1735689600.482is fine to keep: the fraction is seconds, and it is parsed. - Paste it into the Timestamp box and count the digits. Ten means leave Unit on seconds, thirteen means switch it to milliseconds.
- Read the three rows. If the year looks absurd, the unit is wrong; flip the selector and look again.
- Quote the UTC row when you write the finding down for someone else, and note the zone shown next to Local if you quote that instead. A timestamp without its zone starts the next argument.
If the value came out of a JSON body you can pretty-print the payload first with the JSON formatter, and if it came out of a bearer token the JWT decoder will show the exp claim already converted, which is usually the question you were actually asking.
How to turn a date into a timestamp for a query
- Use the Date and time field in the second section. It is a native browser control, so it follows your operating system conventions for date order and for the 12 or 24 hour clock.
- Remember that the value you type is read in your own time zone, not in UTC. If you want the epoch value for midnight UTC, enter the local time that corresponds to it, or convert the wall clock first with the time zone converter.
- Copy the row you need. Seconds is what a shell command, a Postgres
to_timestamp()call or a JWT claim expects; Milliseconds is what a JavaScriptDateor an Android API expects. - For a range, convert both ends and check the difference by hand. One day is 86,400 seconds, one hour is 3,600, one week is 604,800. If the gap is not a round multiple of those and you expected it to be, a daylight saving transition probably sits inside the range.
Getting the number where it needs to go
The large number at the top of the page is the current timestamp in seconds and updates once a second. Click it to copy. The two buttons in the date section copy the seconds and millisecond values. Where the number lands next decides whether anything else needs to change:
- Into a shell: no quoting is needed, it is only digits. To seed a test fixture an hour from now, arithmetic in the shell is easier than copying twice:
echo $(($(date +%s) + 3600)). - Into SQL: paste the seconds value into
to_timestamp()on PostgreSQL orFROM_UNIXTIME()on MySQL rather than into a string comparison, so the database does the conversion and the index still gets used. - Into a spreadsheet: epoch seconds are not a date to Sheets or Excel. Convert with
=A1/86400+DATE(1970,1,1), then format the cell as a date. The result is UTC, so add the offset if you need local time. - Into a ticket or a chat message: paste the ISO 8601 row instead of the integer. Nobody reviewing the ticket in six months will convert the number, and Slack, Jira and GitHub all leave a bare integer as a bare integer.
- On a phone: press and hold the big number to select it if the tap to copy gesture is awkward, then paste with a long press in the destination field. On iOS and on Android the clipboard is shared between apps, so a timestamp copied here pastes straight into a terminal app or a note.
The same conversion in other languages and databases
Every runtime offers both directions, and the only real trap is which unit it hands back. JavaScript is the odd one out, working in milliseconds throughout:
// JavaScript: Date works in milliseconds Date.now() // 1735689600000 Math.floor(Date.now() / 1000) // 1735689600 new Date(1735689600 * 1000).toISOString() // '2025-01-01T00:00:00.000Z'
# Python: seconds, as a float import time from datetime import datetime, timezone time.time() # 1735689600.482 datetime.fromtimestamp(1735689600, tz=timezone.utc) # datetime(2025, 1, 1, 0, 0, tzinfo=timezone.utc) int(datetime.now(timezone.utc).timestamp()) # 1735689600
- Go:
time.Now().Unix()for seconds,UnixMilli()andUnixNano()for the finer units,time.Unix(sec, 0)to go back. - Java:
System.currentTimeMillis()gives milliseconds, whileInstant.now().getEpochSecond()gives seconds. Mixing the two in one codebase is a common source of the factor of a thousand bug. - PHP:
time()anddate('c', $ts). Ruby:Time.now.to_iandTime.at(ts). .NET:DateTimeOffset.UtcNow.ToUnixTimeSeconds(). - Shell:
date +%sworks on Linux and macOS. Going back does not: GNU coreutils wantsdate -d @1735689600, BSD and macOS wantdate -r 1735689600.
-- PostgreSQL
SELECT to_timestamp(1735689600); -- timestamptz
SELECT EXTRACT(EPOCH FROM now())::bigint;
-- MySQL (renders in the session time zone)
SELECT FROM_UNIXTIME(1735689600), UNIX_TIMESTAMP();
-- SQLite
SELECT datetime(1735689600, 'unixepoch');
SELECT strftime('%s', 'now');Two platform details are worth knowing before you design a schema. MySQL FROM_UNIXTIME() renders in the session time zone, so the same query can return different strings for two connections, and the MySQL TIMESTAMP column type is documented as ending at 2038-01-19 03:14:07 UTC, which is the 32-bit limit discussed below. In JWTs, RFC 7519 defines exp, iat and nbf as NumericDate values, meaning seconds and never milliseconds, which is why a token built with Date.now() instead of Date.now() / 1000 appears to expire some 50,000 years from now.
Limits, edge cases and what this page does not do
What leaves your browser: nothing. Every conversion runs locally through the built-in JavaScript Dateobject, and the live clock reads your own device rather than a time server. Nothing you paste is uploaded, stored or logged, so pasting a timestamp copied straight out of a production log is safe. Analytics records only that the page was viewed.
The unit is chosen by you, not detected. The Unit selector defaults to seconds and stays where you put it. If a result is thousands of years out, that is the first thing to check.
2038 is a real deadline for some systems. A signed 32-bit integer reaches its maximum at 2038-01-19 03:14:07 UTC and then wraps to December 1901. Current 64-bit runtimes are unaffected, but embedded controllers, fixed-width file formats and 32-bit database columns are not, and they are exactly the systems nobody is watching. This page uses JavaScript numbers, whose Date range runs to roughly the years -271821 and 275760, so it is not the constraint.
Local means your device, with all that implies. The local row and the date field both read the clock and zone your operating system reports. A machine with the wrong zone set, or a VPN that has changed nothing about the clock, will produce a local reading that disagrees with a colleague looking at the same integer. The UTC row never has this problem, which is the argument for quoting it.
Precision has a floor. Fractional seconds are accepted and preserved in the ISO row, but the local and UTC rows are truncated to whole seconds for readability. If you are comparing events milliseconds apart, work from the raw values rather than from the rendered strings.
Accessibility. The live timestamp is a real button, so it is reachable with the keyboard and announces itself to a screen reader, but it updates every second, and a screen reader set to announce changes will be noisy on this page. The values are laid out with tabular figures and are selectable, so magnification and copy both behave normally.
Frequently asked questions
What is a Unix timestamp?
A Unix timestamp, also called epoch time or POSIX time, is a plain count of seconds since 1970-01-01 00:00:00 UTC. That instant is the epoch, chosen when Unix was built at Bell Labs in the early 1970s. Because it is a single integer measured from a fixed point in UTC, it carries no time zone, no calendar and no formatting, which is exactly why databases, APIs and log files store it instead of a human readable date.
Is my number in seconds or milliseconds?
Count the digits. Ten digits is seconds and covers dates from September 2001 to November 2286. Thirteen digits is milliseconds over the same range, and is what JavaScript Date.now() and Java System.currentTimeMillis() return. Sixteen digits is microseconds, which is what PostgreSQL and many tracing systems use, and nineteen digits is nanoseconds, common in Go and in OpenTelemetry. This page has a Unit selector for seconds and milliseconds; for microseconds or nanoseconds, divide by 1,000 or 1,000,000 first and paste the millisecond value.
Does a Unix timestamp have a time zone?
No, and it cannot have one. The count is defined from an instant in UTC, so the same timestamp describes the same moment everywhere on Earth. A time zone only enters the picture when you display it: 1735689600 is 2025-01-01 00:00 in London, 2024-12-31 19:00 in New York and 2025-01-01 09:00 in Tokyo, all the same instant. Store the integer, convert on display, and record the user preferred zone separately if you need to show it back to them.
Why did my date come out in the year 56000, or in 1970?
Both are unit mistakes. A year far in the future means a millisecond value was read as seconds, so the moment was multiplied by a thousand. A date at or near 1970-01-01 means the field held zero, or a null that a driver quietly turned into zero, or a value in seconds was read as milliseconds. Check the digit count first, then check whether the column really was populated.
Does Unix time count leap seconds?
No. POSIX defines every day as exactly 86,400 seconds, so inserted leap seconds are skipped rather than counted. Twenty seven leap seconds have been added to UTC since 1972, the most recent at the end of 2016, which means a Unix timestamp is not a true count of elapsed SI seconds since the epoch. For almost all application work this does not matter. It matters for precise interval measurement, where a monotonic clock is the right tool anyway. In 2022 the General Conference on Weights and Measures voted to stop inserting leap seconds by 2035.
What is the year 2038 problem?
A signed 32-bit integer tops out at 2,147,483,647, which as a Unix timestamp is 2038-01-19 03:14:07 UTC. One second later it overflows to a large negative number and the date jumps back to December 1901. Current 64-bit operating systems and language runtimes are long past this, but the risk remains in embedded and industrial devices, in file formats that pin the field to 32 bits, and in database columns such as the MySQL TIMESTAMP type, whose documented range ends at that same instant. Use a 64-bit integer, or a MySQL DATETIME column, for anything that has to outlive 2038.
Can a Unix timestamp be negative?
Yes. Negative values are instants before 1970, so -1000000000 is 1938-04-24. JavaScript, Python, Java and Go all handle them, and this page does too. Support is less reliable further down the stack: some older C libraries and some database drivers reject negative values or wrap them, and a few APIs use a negative number as a sentinel for unset. If you are storing historical dates, a date type is usually a better fit than epoch seconds.
How do I get the current Unix timestamp on the command line?
Run date +%s on macOS and on Linux; both print the current time in seconds. To go the other way, GNU coreutils on Linux uses date -d @1735689600, while macOS and other BSD systems use date -r 1735689600. For milliseconds on Linux, date +%s%3N works; macOS date has no millisecond format, so use python3 or node instead.
When should I use ISO 8601 instead of a Unix timestamp?
Use epoch integers between machines, where sorting, arithmetic and equality checks are the point, and where every extra byte in a log line counts. Use ISO 8601, or its stricter internet profile RFC 3339, when a person is going to read the value: configuration files, API documentation, CSV exports and user interfaces. An ISO string such as 2025-01-01T00:00:00Z is self describing and carries its offset, which makes it far harder to misread than a bare integer.
Does anything I paste into this page get uploaded?
No. Every conversion runs in your browser with the built-in JavaScript Date object, and the live clock reads your own device. Nothing you type is sent to a server, stored or logged. Once the page has loaded you can disconnect from the network and it keeps working, which is a useful property when you are pasting timestamps out of production logs.
Sources
- MDN, Date and Date.now() (the millisecond epoch and the representable range used above).
- IETF, RFC 3339, Date and Time on the Internet: Timestamps (the ISO 8601 profile shown in the third result row).
- IETF, RFC 7519, JSON Web Token (NumericDate, and why
expandiatare in seconds). - IANA, Time Zone Database (the zone rules your browser applies to the local row).
- The 86,400 second day comes from the POSIX definition of Seconds Since the Epoch in the Open Group Base Specifications. Leap second counts are published by the IERS, and the decision to retire the leap second was taken by the General Conference on Weights and Measures in 2022. Database behaviour is quoted from the PostgreSQL, MySQL and SQLite manuals and can change between versions.
More developer tools
A timestamp is rarely the whole question. If the number came out of a bearer token, the JWT decoder shows the expiry already converted; if it came out of an API response, the JSON formatter will make the payload readable first. For wall clock work across offices the time zone converter is the better fit, and for a plain question about how long ago a date was, the age calculator counts the years and days for you.
Related tools
- Time Zone Converter
Convert a time across 90 world cities at once, from New York and London to Tokyo and Sydne…
- JWT Decoder
Paste a JSON Web Token to decode its header and payload, see the expiry (exp) as a readabl…
- JSON Formatter and Validator
Pretty-print or minify JSON in your browser with 2-space, 4-space or tab indentation.
- Base64 Encode and Decode
Convert text to Base64 and back with full UTF-8 support, so accented letters, CJK and emoj…
- UUID Generator (v4 and v7)
Generate UUID v4 (random) or UUID v7 (time-ordered) identifiers in bulk and copy them with one click.
Privacy: the clock and every conversion run in your browser with the built-in JavaScript Date object. Nothing you paste is uploaded, stored or logged, and the page keeps working with the network disconnected. Analytics records only that the page was viewed.
