The Year 2038 problem
On this page
TL;DR. On 2038-01-19 03:14:07 UTC, the signed 32-bit Unix timestamp overflows from
2147483647to-2147483648, making the system think it’s 1901. Most modern Linux/Unix systems already use 64-bittime_t, but embedded systems, old databases, file formats, and protocols may still be 32-bit. Audit now.
What overflows, exactly
A signed 32-bit integer holds values from -2147483648 to +2147483647.
For Unix seconds, that range covers:
-2,147,483,648 = 1901-12-13 20:45:52 UTC
0 = 1970-01-01 00:00:00 UTC (the epoch)
2,147,483,647 = 2038-01-19 03:14:07 UTC
At the moment of 2147483647 + 1, the value wraps to -2147483648 —
the system interprets the new “now” as 1901-12-13 20:45:52 UTC.
The exact moment
Tuesday, January 19, 2038 at 03:14:07 UTC
= Monday, January 18, 2038 at 22:14:07 EST
= Tuesday, January 19, 2038 at 12:14:07 JST
You can paste 2147483647 into the converter and see the date
yourself.
What’s affected
Definitely safe (64-bit time_t)
- Linux x86_64 — 64-bit since the architecture was introduced.
- macOS x86_64 / arm64 — 64-bit
time_tsince 10.6 (2009). - Windows — the C runtime’s
time_thas been 64-bit by default since Visual C++ 2005, and the Windows API’s own clock is a 64-bit count that isn’t affected. - iOS, Android (modern) — 64-bit on all current devices.
- Modern PostgreSQL —
timestampandtimestamptzare not limited to 2038 (they run to year 294276). For other databases, check the date type’s documented range. - Modern programming languages — JavaScript,
Python
int(arbitrary precision), Go (64-bit by default).
For these, Y2038 is a non-issue. The 64-bit range covers ~292 billion years — well past any practical horizon.
Potentially affected (32-bit time_t)
- Embedded systems — IoT devices, industrial controllers, vehicle electronics, point-of-sale terminals running old Linux kernels.
- 32-bit Linux — the kernel gained 64-bit
time_tsupport in version 5.6 (2020) and glibc in 2.34 (2021), but software has to be built to use it. Check your kernel, glibc and build flags. - Old file formats —
tar(resolved in modern versions),zip(now stretched),cpio. - Some embedded databases — older SQLite versions; modern SQLite is fine.
- Legacy industrial protocols — Modbus and similar that pack timestamps into 32-bit fields.
- Old GPS firmware — some had Y2038-related rollovers separate from the GPS Week Number rollover (which already happened in 2019).
Definitely affected (without action)
- C/C++ code on 32-bit platforms that explicitly uses
int32_tor legacytime_t. Check ports of older Unix software running on embedded ARM or MIPS. - Database
INTEGERcolumns holding timestamps explicitly typed as 32-bit. Many systems silently promoted these to BIGINT, but decade-old apps may not have been updated. - Some old HTTP cookie expirations — old browsers stored cookie expiry as 32-bit time.
- MySQL
TIMESTAMPcolumns — limited to2038-01-19 03:14:07UTC. UseDATETIMEfor dates after that.
Real incidents already
The Year 2038 problem has already caused at least one real failure. In May 2006, some AOLserver web servers began hanging or crashing at around 9:25 p.m. US Eastern on May 12, in the early hours of May 13 UTC. Many of these servers had database timeout settings (MaxOpen and MaxIdle) of one billion seconds, a value commonly used to mean “never time out”. That was one billion seconds before 03:14:08 UTC on January 19, 2038, the first second a signed 32-bit Unix time cannot hold. Adding one billion seconds to the current time produced a number too large for a signed 32-bit integer. It wrapped to a negative value. On Solaris the server crashed, and on Linux its scheduled tasks stopped running. Setting the timeouts to 0 or to a modest value such as 3600 seconds, then restarting the server, fixed it. Only servers with those settings were affected, which shows how a 2038 bug can appear decades early whenever software adds a large offset to the current time.
Sources: Dossy Shiobara on the AOLserver list, May 17, 2006, Michael A. Cleverly’s explanation and Dossy Shiobara’s round-up, August 9, 2006.
Code that sets dates years ahead, such as expiry, licence or audit dates, can fail long before 2038.
How to check your stack
# C check
cat <<'EOF' > t.c
#include <stdio.h>
#include <time.h>
int main(void) {
printf("sizeof(time_t) = %zu\n", sizeof(time_t));
return 0;
}
EOF
gcc t.c -o t && ./t
# Want: 8
# Database — Postgres
\d+ table_name
# Look for timestamp / bigint columns; INTEGER on time fields is suspect
# Application code — search for hard-coded 2147483647 or 0x7FFFFFFF
grep -r 2147483647 .
grep -r 0x7FFFFFFF .
If your timestamps are stored as 32-bit anywhere, plan a migration to 64-bit before 2038. The fix is mechanical (column type change + data copy) but disruptive in production.
Languages that handle it natively
- JavaScript / Node —
Date.now()returns milliseconds since the epoch as a number, andDatesupports dates up to September 13, 275760. - Python
int— arbitrary precision; no overflow ever. - Go
time.Time— usesint64seconds internally. - Rust
chrono::DateTime—i64based. - Java 8+
Instant—longseconds + nanoseconds.
If your application code is in any of these on a 64-bit OS, you can ignore Y2038 for application-level time. The risk lives in:
- Stored data (database column types)
- External systems (embedded devices, legacy mainframes)
- Wire protocols (any that hardcode a 32-bit timestamp field)
What to do today
- Audit any 32-bit
inttimestamp columns in your databases. Migrate to 64-bit. Most modern ORMs default to 64-bit but check. - Update embedded device firmware if you ship hardware with a long service life. A 2026 device that’s expected to run for 15 years will hit 2038.
- Avoid hardcoding 2147483647 as a “max date” sentinel — use the
language’s
MAX_VALUEfor the actual integer type, or store NULL. - Test with future dates. Set a system clock to 2038-02 in a sandbox and run your test suite. Things that break will surface.
Tools
Paste these into the Unix timestamp converter to see for yourself. For the value ticking right now, open Current Unix timestamp (live).
2147483647— last 32-bit second2147483648— first second past the cliff. The converter reads it as seconds (2038-01-19 03:14:08 UTC), because it’s under 10^11.2147483647000— the last 32-bit second, expressed in milliseconds (still fine in JavaScript / 64-bit world)
Related reading
- What is Unix epoch? — the basics
- Seconds vs milliseconds — the most common time bug
- Wikipedia: Year 2038 problem — comprehensive
Related across the network
- date.tooljo.com — UTC-anchored date math that doesn’t trip the Y2038 boundary at all (uses ms-precision).
- date.tooljo.com/date-format-reference — covers how each format handles the post-2038 transition.
- jwt.tooljo.com/standard-claims
— JWT
expis Unix seconds; check whether your library’s parser uses 32- or 64-bit integers.