The Year 2038 problem: what a 32-bit timestamp does
A signed 32-bit Unix timestamp runs out at 03:14:07 UTC on 19 January 2038. Type any number of seconds to see what a 32-bit field would store and what it would be read as, and watch the rollover second by second. Nothing you type leaves your browser.
The tool
Store a time in 32 bits
The rollover, second by second
Countdown to 2038-01-19 03:14:08 UTC
How to use
- Type a whole number of seconds since 1970-01-01T00:00:00Z in the box (negative numbers are before 1970). The buttons fill in the interesting values.
- The big line says what a signed 32-bit
time_tholding that number would mean when read back. If the number fits, that is the real date. If it does not fit, the stored value has wrapped around and the line shows the wrong date a program would see. - The table below it gives the real UTC time, the stored value and the date it is read as, for both a signed and an unsigned 32-bit field.
- The second table steps through the rollover: the last second that fits, the first that does not, and the neighbours.
- The countdown shows the time from now (your device clock) until 03:14:08 UTC on 19 January 2038. After that moment it reads "Already passed" and shows how long ago it was. It uses your device's clock and nothing else.
Worked examples
Every result printed here is recomputed by an automated test. The wrap uses exact integer arithmetic (BigInt), and the instants are also checked against JavaScript's Date in the tests.
The key instants of a 32-bit count
| Seconds | UTC | What it is |
|---|---|---|
-2147483648 | 1901-12-13T20:45:52Z | Smallest signed 32-bit value, -2^31 |
0 | 1970-01-01T00:00:00Z | Zero: the Unix epoch |
2147483647 | 2038-01-19T03:14:07Z | Largest signed 32-bit value, 2^31 - 1 |
2147483648 | 2038-01-19T03:14:08Z | 2^31: one second after the largest signed 32-bit value (does not fit) |
4294967295 | 2106-02-07T06:28:15Z | Largest unsigned 32-bit value, 2^32 - 1 |
4294967296 | 2106-02-07T06:28:16Z | 2^32: one second after the largest unsigned 32-bit value (does not fit) |
The rollover
Input: 2147483647
Result: real 2038-01-19T03:14:07Z; signed 32-bit stores 2147483647 = 2038-01-19T03:14:07Z; unsigned 32-bit stores 2147483647 = 2038-01-19T03:14:07Z
Input: 2147483648
Result: real 2038-01-19T03:14:08Z; signed 32-bit stores -2147483648 = 1901-12-13T20:45:52Z; unsigned 32-bit stores 2147483648 = 2038-01-19T03:14:08Z
One second after the last good value, a signed 32-bit field reads as 13 December 1901, 68 years before the epoch. An unsigned field still has room: it reads 03:14:08, the correct time, and keeps going until 2106.
The unsigned limit in 2106
Input: 4294967295
Result: real 2106-02-07T06:28:15Z; signed 32-bit stores -1 = 1969-12-31T23:59:59Z; unsigned 32-bit stores 4294967295 = 2106-02-07T06:28:15Z
Input: 4294967296
Result: real 2106-02-07T06:28:16Z; signed 32-bit stores 0 = 1970-01-01T00:00:00Z; unsigned 32-bit stores 0 = 1970-01-01T00:00:00Z
An unsigned 32-bit counter wraps to 0, which both readings show as the epoch itself.
The other end: dates before 1901
Input: -2147483648
Result: real 1901-12-13T20:45:52Z; signed 32-bit stores -2147483648 = 1901-12-13T20:45:52Z; unsigned 32-bit stores 2147483648 = 2038-01-19T03:14:08Z
Input: -2147483649
Result: real 1901-12-13T20:45:51Z; signed 32-bit stores 2147483647 = 2038-01-19T03:14:07Z; unsigned 32-bit stores 2147483647 = 2038-01-19T03:14:07Z
A birth date in 1900 stored as a signed 32-bit count wraps forward to 2038. This is the same limit at the other end.
An ordinary date
Input: 1700000000
Result: real 2023-11-14T22:13:20Z; signed 32-bit stores 1700000000 = 2023-11-14T22:13:20Z; unsigned 32-bit stores 1700000000 = 2023-11-14T22:13:20Z
How long is left, from a fixed moment
Input: 1790812800
Result: 1790812800 = 2026-10-01T00:00:00Z; 356670848 s until 2147483648 (4128 d 3 h 14 min 8 s)
This is counted from a fixed instant, 00:00 UTC on 1 October 2026 (Thursday), not from the moment you read this, so the numbers on this page never change. From that instant the signed limit was 356,670,848 seconds away, a little over 11 years. For the live figure, use the countdown in the demo above: it is computed from your device's clock every second.
What goes wrong
"We have until 2038"
Software that handles dates in the future reaches the limit early. A 30-year loan or a 20-year certificate created in 2026 has an end date (2056 or 2046) after 2038-01-19, and cannot be stored in a signed 32-bit field. Try 2208988800 (the first second of 2040) in the converter above: a signed 32-bit field would read it back as 25 November 1903.
Input: 2208988800
Result: real 2040-01-01T00:00:00Z; signed 32-bit stores -2085978496 = 1903-11-25T17:31:44Z; unsigned 32-bit stores 2208988800 = 2040-01-01T00:00:00Z
"A 64-bit machine is safe"
Only the data held in 64-bit fields is safe. File formats, protocols and database columns defined with 32 bits stay limited when the CPU is 64-bit (see the MySQL TIMESTAMP example in the FAQ).
Confusing signed and unsigned
The same stored 32 bits read as 1901 when interpreted as signed and as 2038 when interpreted as unsigned. Two systems that share a file can disagree about a date without either being buggy. The table in the live demo shows both readings of each value.
Mixing it up with the 2036 NTP rollover or with Y2K
NTP's 32-bit field counts from 1900 and wraps in 2036; Y2K was about two-digit years in decimal. Different epochs, different limits, different fixes.
Limits & gotchas
- The demo is arithmetic, not an emulation. It shows what the integer wrap means, using two's complement. It cannot tell you what your program, library or database does at that moment.
- Which systems are affected is not listed here. The page states what the sources say (the Linux kernel documentation on 32-bit architectures, glibc's
_TIME_BITS=64, the MySQL TIMESTAMP range) and does not claim to audit any product. Check the documentation of the product you use. - The countdown uses your device's clock, which can be wrong. Leap seconds are not counted: a Unix timestamp ignores them, so the counter reaches 2147483648 at exactly 03:14:08 UTC as the clocks of Unix-time systems show it.
- The 2036 NTP figure is an arithmetic result from the NTP epoch (1900-01-01) and is checked against the era table in RFC 5905; it describes the field, not the behaviour of any NTP implementation.
- Whole seconds only. The demo takes integers; a fraction is refused because a 32-bit
time_thas none.
FAQ
What exactly happens at 03:14:08 UTC on 19 January 2038?
A time_t that is a signed 32-bit integer counts seconds since 1970-01-01T00:00:00Z and tops out at 2147483647, which is 03:14:07 UTC on 19 January 2038. The next second needs 2147483648, which does not fit; in two's-complement arithmetic the counter wraps to -2147483648, which reads as 20:45:52 UTC on 13 December 1901. The live demo above shows the second-by-second sequence.
Does this affect my 64-bit computer?
A 64-bit time_t does not run out in 2038 (a signed 64-bit count of seconds lasts for hundreds of billions of years). The Linux kernel documentation describes the overflow of the tv_sec member as a problem on 32-bit architectures, and glibc 2.34 and later can be asked to use a 64-bit time_t on 32-bit systems with _TIME_BITS=64. But a 64-bit CPU does not protect data that was written elsewhere as 32 bits: a file format, a network protocol or a database column can still hold a 32-bit count. MySQL's TIMESTAMP type is a documented example: its range ends at 2038-01-19 03:14:07 UTC.
Is it only a problem in 2038?
No, and that is the useful point. Any program that stores a date after 2038-01-19T03:14:07Z in a signed 32-bit field fails as soon as it is stored: a certificate, a contract or a loan whose end date is in 2040 cannot be stored. And an unsigned 32-bit counter, which is how some systems avoid the sign, has the same wrap later, at 06:28:16 UTC on 7 February 2106. Use the converter above with 2147483648 or 4294967296 to see what each reads back as.
Is the 2038 problem the same as the NTP era rollover in 2036?
They are separate. NTP counts seconds since 1900-01-01 in an unsigned 32-bit field, and RFC 5905 says that field wraps in 2036 when era 1 begins: 2^32 seconds after 1900-01-01T00:00:00Z is 06:28:16 UTC on 7 February 2036. The RFC's era table lists 8 February 2036 as the first day of era 1 with an era offset of 63,104 seconds, and 63,104 is exactly the time from 06:28:16 UTC on 7 February to the following midnight (86,400 minus 23,296), so the table and the arithmetic agree. The point here is that 32-bit time fields wrap at different moments depending on their epoch.
How do I fix it?
Store and compute times in 64 bits (or in a type whose documented range covers the dates you need), and test with dates beyond 2038 before you ship: in a column, a file, a message and a library. PostgreSQL's timestamp types, for example, are documented as covering 4713 BC to 294276 AD with microsecond resolution, and a JavaScript Date covers the years -271821 to 275760. If you cannot change a 32-bit format, decide explicitly what the wrap means (for example, treating the field as unsigned) and write it down.
Sources
- Wikipedia: Year 2038 problem Used for: A signed 32-bit time_t overflows at 03:14:07 UTC on 19 January 2038 and wraps to 20:45:52 UTC on 13 December 1901.
- The Linux kernel documentation: timekeeping: ktime accessors Used for: The statement that the tv_sec member overflows in the year 2038 on 32-bit architectures.
- man7.org (Linux man-pages): feature_test_macros(7) Used for: _TIME_BITS=64 makes time_t 64-bit in glibc 2.34 and later (the way to avoid the 2038 limit on 32-bit systems that use glibc).
- Oracle: MySQL 8.4 Reference Manual: The DATE, DATETIME, and TIMESTAMP Types Used for: TIMESTAMP has a range of '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC; TIMESTAMP values are converted from the connection's time zone to UTC for storage and back on retrieval, so changing the time zone changes the value read back.
- PostgreSQL Global Development Group: PostgreSQL 18: Date/Time Types Used for: timestamp and timestamptz have a range of 4713 BC to 294276 AD with 1 microsecond resolution.
- IETF (RFC Editor): RFC 5905: Network Time Protocol Version 4, section 6 (time scale and era table) Used for: NTP timestamps count seconds from 1900-01-01 in an unsigned 32-bit field that wraps around in 2036 when era 1 begins; the era table lists 8 Feb 2036 as the first day of era 1 with an era offset of 63,104 seconds.
- The Open Group: POSIX.1-2024 Base Definitions, 4.19 Seconds Since the Epoch Used for: Seconds since the Epoch "approximates" the seconds elapsed since the Epoch; the formula that relates a UTC date to it for years from 1970 and non-negative values; "If the year is <1970 or the value is negative, the relationship is undefined"; "each and every day shall be accounted for by exactly 86400 seconds" (so leap seconds are not counted); the relationship to actual UTC is unspecified.
- MDN Web Docs: Date Used for: The supported range (April 20, 271821 BC to September 13, 275760 AD, plus or minus 100,000,000 days); that Date ignores leap seconds; Number.MAX_SAFE_INTEGER is 9,007,199,254,740,991; the date-time string format (a simplification of ISO 8601, 24:00:00 allowed, expanded years of + or - followed by six digits, -000000 disallowed); and that setting a local time inside a DST transition follows the Temporal "compatible" disambiguation: if the local time corresponds to two instants the earlier one is chosen, and if it does not exist the result goes forward by the gap duration (with the New York 2024 example).
Every document above was opened and read on 2026-10-03. Documentation changes; if a page here disagrees with the current docs, trust the docs and tell us.