Unix Timestamp Reference: Epoch Values and Conversions
Notable epoch values, per-database SQL conversions and the 2038 limits.
No signup, no trackingA Unix timestamp is a single integer: the number of seconds elapsed since 1 January 1970 at 00:00:00 UTC. It carries no timezone, no formatting and no ambiguity, which is exactly why databases, log files, JWTs and APIs reach for it constantly. The cost of that simplicity is that a raw epoch value is unreadable to a human — 1700000000 could be last week or last decade.
This page is the lookup table for that problem. Below you will find notable epoch values with their exact UTC dates, a quick way to tell seconds from milliseconds by counting digits, the conversion expression for every major SQL engine, and the boundary values where 32-bit time runs out. Every date on this page was computed rather than recalled.
Seconds or milliseconds? Count the digits
The single most common bug when handling epochs is feeding a millisecond value into a function that expects seconds, which lands you somewhere around the year 58,000. You almost never need to guess: the magnitude of the number tells you the unit. For any date in the current era, digit count alone is decisive.
| Digits | Unit | Same instant expressed as |
|---|---|---|
| 10 | Seconds | 1785287134 |
| 13 | Milliseconds | 1785287134000 |
| 16 | Microseconds | 1785287134000000 |
| 19 | Nanoseconds | 1785287134000000000 |
| 18 | .NET ticks (100 ns since 0001-01-01) | 639208839340000000 |
| 18 | Windows FILETIME (100 ns since 1601-01-01) | 134297607340000000 |
| 5 | Excel serial day number | 46232 |
If a value is 13 digits and ends in three zeros it is almost certainly milliseconds produced from a whole-second source. Java, JavaScript and Kafka default to milliseconds; C, Python, Go, PostgreSQL and the Unix shell default to seconds. JWT claims (iat, exp, nbf) are always seconds per RFC 7519, which trips up JavaScript developers constantly because Date.now() is not.
Notable epoch values
| Epoch (seconds) | UTC date and time | Why it matters |
|---|---|---|
| 0 | 1970-01-01 00:00:00 UTC | The epoch itself |
| 1 | 1970-01-01 00:00:01 UTC | One second after the epoch |
| 86400 | 1970-01-02 00:00:00 UTC | Exactly one day |
| 1000000000 | 2001-09-09 01:46:40 UTC | The "billennium" — widely celebrated by Unix people |
| 1234567890 | 2009-02-13 23:31:30 UTC | Sequential digits — the classic test value |
| 1500000000 | 2017-07-14 02:40:00 UTC | Round 1.5 billion |
| 1600000000 | 2020-09-13 12:26:40 UTC | Round 1.6 billion |
| 1700000000 | 2023-11-14 22:13:20 UTC | Round 1.7 billion |
| 1735689600 | 2025-01-01 00:00:00 UTC | Start of 2025, UTC |
| 1767225600 | 2026-01-01 00:00:00 UTC | Start of 2026, UTC |
| 1800000000 | 2027-01-15 08:00:00 UTC | Round 1.8 billion |
| 2000000000 | 2033-05-18 03:33:20 UTC | Round 2 billion |
| 2145916800 | 2038-01-01 00:00:00 UTC | Start of 2038 — the last new year signed 32-bit time survives |
| 2147483647 | 2038-01-19 03:14:07 UTC | INT32 maximum — the Year 2038 problem |
| 2147483648 | 2038-01-19 03:14:08 UTC | One second later — wraps to 1901 if stored as signed 32-bit |
| 4294967295 | 2106-02-07 06:28:15 UTC | UINT32 maximum |
| -1 | 1969-12-31 23:59:59 UTC | One second before the epoch |
| -2147483648 | 1901-12-13 20:45:52 UTC | INT32 minimum |
| 253402300799 | 9999-12-31 23:59:59 UTC | Last second of year 9999 — a common upper bound |
Converting epoch to date in SQL
Every engine spells this differently, and the differences are not cosmetic — they affect the return type and the timezone. The left column converts an epoch in seconds to a timestamp; the right column goes back the other way.
| Engine | Epoch to date | Date to epoch |
|---|---|---|
| PostgreSQL | to_timestamp(1700000000) | EXTRACT(EPOCH FROM ts)::bigint |
| MySQL / MariaDB | FROM_UNIXTIME(1700000000) | UNIX_TIMESTAMP(dt) |
| SQL Server | DATEADD(SECOND, 1700000000, '19700101') | DATEDIFF_BIG(SECOND, '19700101', dt) |
| Oracle | TIMESTAMP '1970-01-01 00:00:00' + NUMTODSINTERVAL(1700000000, 'SECOND') | (CAST(ts AS DATE) - DATE '1970-01-01') * 86400 |
| SQLite | datetime(1700000000, 'unixepoch') | CAST(strftime('%s', dt) AS INTEGER) |
Three caveats that cause real incidents. PostgreSQL’s to_timestamp returns timestamp with time zone, so it renders in the client’s TimeZone setting rather than UTC — append AT TIME ZONE 'UTC' if you need a stable display. MySQL’s FROM_UNIXTIME is documented to return the value in the session time zone, so the same query gives different answers to two different clients. And on SQL Server 2017 through 2022 the number argument to DATEADD is an int, so DATEADD(MILLISECOND, 1700000000000, ...) overflows; convert milliseconds in two steps instead.
-- SQL Server: milliseconds without int overflow
SELECT DATEADD(MILLISECOND, 1700000000000 % 1000,
DATEADD(SECOND, 1700000000000 / 1000, '19700101'));
-- PostgreSQL: force a UTC rendering
SELECT to_timestamp(1700000000) AT TIME ZONE 'UTC';Converting in code
| Language | Epoch to date | Now as epoch |
|---|---|---|
| Python | datetime.fromtimestamp(1700000000, tz=timezone.utc) | int(dt.timestamp()) |
| JavaScript | new Date(1700000000 * 1000) | Math.floor(Date.now() / 1000) |
| Go | time.Unix(1700000000, 0).UTC() | t.Unix() |
| Java | Instant.ofEpochSecond(1700000000) | instant.getEpochSecond() |
| PHP | date("Y-m-d H:i:s", 1700000000) | time() |
| Ruby | Time.at(1700000000).utc | t.to_i |
| Bash (GNU) | date -u -d @1700000000 | date +%s |
| PowerShell | [DateTimeOffset]::FromUnixTimeSeconds(1700000000) | [DateTimeOffset]::UtcNow.ToUnixTimeSeconds() |
Excel and Google Sheets
Spreadsheets do not store epochs at all. They store a serial day number counted from 30 December 1899, so converting means dividing by the number of seconds in a day and adding the constant 25569 — the serial number of 1 January 1970. Format the result cell as a date afterwards or you will just see a decimal.
=A1/86400 + 25569 → epoch seconds to date
=A1/86400000 + 25569 → epoch milliseconds to date
=(A1 - 25569) * 86400 → date back to epoch secondsThe constant 25569 looks arbitrary but is not: it includes an off-by-one that Excel inherited deliberately. Excel treats 1900 as a leap year, which it was not, so its serial numbers are one day ahead of reality for any date after February 1900. Because 25569 was derived under the same wrong assumption, the two errors cancel and dates from 1970 onward come out correct.
The 2038 problem and other boundaries
A signed 32-bit integer stops at 2,147,483,647. A system storing Unix time that way runs out of room at 03:14:07 UTC on 19 January 2038, and the next second wraps around to December 1901. This is not hypothetical for embedded devices, older filesystems and any schema that chose INT instead of BIGINT.
| Value | Instant | What breaks |
|---|---|---|
| 2147483647 | 2038-01-19 03:14:07 UTC | Signed 32-bit seconds overflow — the Year 2038 problem |
| 4294967295 | 2106-02-07 06:28:15 UTC | Unsigned 32-bit seconds overflow |
| -2147483648 | 1901-12-13 20:45:52 UTC | Lowest value a signed 32-bit epoch can hold |
| 253402300799 | 9999-12-31 23:59:59 UTC | Last second of year 9999 — upper bound of many SQL date types |
| 8640000000000000 (ms) | +275760-09-13 | Maximum value a JavaScript Date can represent |
The fix is unglamorous: store epochs in 64-bit columns. A signed 64-bit second count runs out roughly 292 billion years from now, which is comfortably past the point where it stops being your problem. If you are choosing a column type today, BIGINT or a native timestamp type are both fine; INT is a dated landmine.
Gotchas worth knowing
- Unix time ignores leap seconds. POSIX requires every day to be exactly 86,400 seconds, so the 27 leap seconds inserted into UTC since 1972 are simply not counted. An epoch value is a calendar calculation, not a tally of elapsed physical seconds.
- An epoch has no timezone. The number is always UTC-based; the timezone only enters when you format it. Two servers showing different dates for the same integer are formatting differently, not storing differently.
- Negative epochs are legal and mean dates before 1970. Plenty of libraries and a few databases handle them badly, so test if you store birthdates this way.
- Watch for epochs stored as strings. Sorting "9999999999" against "10000000000" lexicographically puts them in the wrong order, and the bug only appears once the digit count changes.
- Seconds-resolution timestamps cannot express ordering within the same second. If you need to sequence events, store milliseconds or add a tiebreaker column.
Convert your own values
This table covers the values people look up repeatedly, but not the one sitting in your log file right now. The Unix Timestamp Converter on this site takes any epoch and shows it in your local timezone, in UTC and as ISO 8601 at once, auto-detects whether you pasted seconds or milliseconds, and runs the conversion in reverse from a date picker. It also keeps a live current timestamp ready to copy. Like everything here it runs entirely in your browser — the values you paste are never uploaded anywhere.