Year 2038 Problem
In brief: Many computers count time as the number of seconds since 1 January 1970. On systems that store that count in a signed 32-bit number, the count runs out at 03:14:07 UTC on 19 January 2038. One second later the number "wraps around" and the computer thinks it is December 1901. Most modern desktops, servers and phones are already fixed, but older software, 32-bit embedded devices, file formats and databases that still use 32-bit time can fail. Some of them fail years early, as soon as they handle a date after 2038.
| Risk level | High (Critical for long-lived 32-bit embedded and industrial systems) |
| Status | Fixed in most current OS kernels and C libraries. Legacy 32-bit binaries, on-disk formats, protocols and embedded fleets are still at risk |
| Last reviewed | 2026-10-21 |
Overview
What time_t is
Unix and Unix-like systems, and the C language they spawned, represent a moment in time as a single integer: the number of seconds since the Unix epoch, 1970-01-01 00:00:00 UTC. The C type that holds the count is time_t. Functions such as time(), gmtime(), mktime() and stat(), together with the timestamps of almost every file on a Unix file system, are built on it. The same "seconds since 1970" convention spread well beyond C and Unix. It turns up in network protocols, database column types, file formats, embedded firmware, and the runtimes of languages such as Java, PHP and Python.
For decades time_t was a signed 32-bit integer on most platforms, because long was 32 bits wide on the 16- and 32-bit machines where Unix grew up. A signed 32-bit integer holds values from −2,147,483,648 to +2,147,483,647, so it can represent:
| Value | Meaning (UTC) |
|---|---|
| −2,147,483,648 (−2³¹) | Fri 1901-12-13 20:45:52 |
| 0 | Thu 1970-01-01 00:00:00 (the epoch) |
| 1,000,000,000 | Sun 2001-09-09 01:46:40 ("Unix billennium") |
| 2,147,483,647 (2³¹ − 1) | Tue 2038-01-19 03:14:07 |
| 4,294,967,295 (2³² − 1, if unsigned) | Sun 2106-02-07 06:28:15 |
The exact overflow moment
At 2038-01-19 03:14:07 UTC a signed 32-bit time_t reaches its maximum value. Adding one more second causes an integer overflow. On two's-complement hardware, which is effectively all hardware, the value wraps to −2,147,483,648. Software then reads that value as 1901-12-13 20:45:52 UTC [1][2]. Depending on the program, the result can be a date shown in 1901, a negative interval, a timer that never fires or fires at once, an expired certificate, a failed mktime() that returns −1, or a crash.
Why signed 32-bit?
time_t was signed so that dates before 1970 could be stored as negative numbers, and so that subtracting two times gives a negative difference without special handling. The cost is that half the range is spent on 1901–1970, so the forward range ends in 2038 and not in 2106. Some systems took the opposite trade-off: they made the 32-bit count unsigned, which pushes the limit to 2106 but makes pre-1970 dates unrepresentable. OpenBSD [3], glibc's utmp/lastlog records [4], Linux struct input_event [5] and QNX before SDP 8.0 [6] all made this choice in some form. See Year-2106-and-Beyond.
Technical details
Worked binary example
The largest signed 32-bit value has a 0 sign bit followed by thirty-one 1s:
2147483647 = 0111 1111 1111 1111 1111 1111 1111 1111 -> 2038-01-19 03:14:07 UTC
+ 1
-----------------------------------------------------------------------------
-2147483648 = 1000 0000 0000 0000 0000 0000 0000 0000 -> 1901-12-13 20:45:52 UTC
The bit pattern 0x80000000 is exactly 2³¹. In a signed two's-complement interpretation the top bit is the sign bit and carries a weight of −2³¹. The same bits that meant "one second after 2038-01-19 03:14:07" therefore now mean "2,147,483,648 seconds before 1970". In C, signed overflow is formally undefined behaviour, so an optimising compiler is free to do something even stranger than wrapping.
You can reproduce the two endpoints with GNU date:
$ date -u -d @2147483647
Tue 19 Jan 2038 03:14:07 UTC
$ date -u -d @-2147483648
Fri 13 Dec 1901 20:45:52 UTC
A minimal C demonstration of how a 32-bit counter misbehaves:
#include <stdint.h>
#include <stdio.h>
#include <time.h>
int main(void) {
int32_t t32 = INT32_MAX; /* 2038-01-19 03:14:07 UTC */
t32 = (int32_t)((uint32_t)t32 + 1u); /* wrap explicitly (defined behaviour) */
time_t t = t32; /* widen to the platform's time_t */
printf("%s", asctime(gmtime(&t))); /* Fri Dec 13 20:45:52 1901 */
printf("sizeof(time_t) = %zu\n", sizeof(time_t));
return 0;
}
The fix: 64-bit time_t
A signed 64-bit time_t gives a range of about ±292 billion years, which in practice removes the problem. The underlying change is simple. Deploying it is not, because time_t is embedded in ABIs (struct stat, struct timespec, struct timeval, struct utmp, ioctl structures, library interfaces), in on-disk formats and in wire protocols. Widening the type changes struct layouts, so binaries and libraries compiled against the old size become incompatible with the new one. This is why the fix took decades on 32-bit platforms:
- 64-bit platforms (LP64: x86-64, AArch64, ppc64, RISC-V 64 and others) have used a 64-bit
time_tfrom their first day on Linux, the BSDs, macOS and Solaris. - 32-bit platforms needed new kernel system calls, new C-library entry points, and a rebuild of the whole userland. On Linux this took from roughly 2014 to 2024. See OS-Linux.
- Standards: POSIX.1-2024 (Issue 8) now requires that "
time_tshall be an integer type with a width … of at least 64 bits" [7][8].
Not just time_t
A 64-bit time_t does not help when a timestamp is squeezed back into 32 bits somewhere else. Common hiding places include:
- On-disk timestamps: ext2/ext3 and ext4 with 128-byte inodes, XFS without
bigtime, UFS1, HFS+ (2040). See File-Systems. - Database column types and functions such as
TIMESTAMPandUNIX_TIMESTAMP(). See Databases. - Binary file and network formats with 32-bit seconds fields, such as
utmp/wtmp, PE headers, cpio and many proprietary formats. See File-Formats-and-Protocols. - Application code that casts
time_ttointorlong, or that stores it in a 32-bit field of a struct. - Related counters with different rollover dates: NTP era 0 ends in 2036 (NTP-Era-2036) and GPS week numbers roll over every 1024 weeks (GPS-Week-Rollover).
History of awareness
| Year | Milestone |
|---|---|
| 1990s | Developers discuss the 2038 limit in the context of Y2K and the move to 64-bit (LP64) Unix. A November 1997 thread on the tz mailing list already discusses time_t and LP64 [9]. See Year-2000-Problem. |
| 2000 | A January 2000 linux-kernel thread titled "time_t size: The year 2038 bug?" argues over whether to widen time fields in new 64-bit ABIs [10]. |
| 2001-09-09 | time_t passes 1,000,000,000. This is a cosmetic milestone, but it exposed software that sorted or formatted timestamps as strings. |
| 2006-05-13 | AOLserver fails because a one-billion-second timeout, added to the current time, overflowed past 2038 [2]. |
| 2012 | NetBSD 6.0 ships a 64-bit time_t on all ports [11]. |
| 2013 | LWN's "Pondering 2038" describes the Linux options. OpenBSD commits its 64-bit time_t change [12]. |
| 2014 | OpenBSD 5.5 (May 2014) is "year 2038 ready" [3]. Arnd Bergmann posts the first Linux y2038 patch series for inode timestamps [13]. |
| 2015–2018 | Linux kernel conversion work, including Deepa Dinamani's Outreachy VFS work, merged in 2018 [14]. |
| 2019 | Linux 5.1 adds the *_time64 system calls for 32-bit architectures [5][15]. |
| 2020 | musl 1.2.0 switches all 32-bit architectures to 64-bit time_t [16]. Linux 5.6 is "the first release that can serve as a base for a 32-bit system designed to run beyond year 2038" [5]. |
| 2021 | glibc 2.34 adds _TIME_BITS=64 for legacy 32-bit ABIs [4]. |
| 2022-01-01 | Microsoft Exchange's "Y2K22" bug: a date-based version number overflowed a signed 32-bit integer [17]. See OS-Windows. |
| 2024 | Debian (February 2024 onward) and Ubuntu 24.04 LTS move armhf to 64-bit time_t [18][19]. POSIX.1-2024 requires a time_t of at least 64 bits [8]. |
| 2025 | Debian 13 "trixie" (2025-08-09) ships with a 64-bit time_t ABI on every architecture except i386 [20]. FreeBSD 15.0 retires i386 [21]. |
Current state of industry fixes (as of 2026-10-21)
| Layer | State | Details |
|---|---|---|
| 64-bit OSes (Linux, BSD, macOS, Windows, Solaris/illumos 64-bit userland) | Fixed | 64-bit time_t by design. Remaining issues lie in file systems, formats and applications. |
| Linux kernel (32-bit) | Fixed in 5.6+ | Legacy 32-bit syscalls are kept for compatibility [5]. |
| glibc (32-bit) | Opt-in since 2.34 | -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64 [4]. |
| musl (32-bit) | Default since 1.2.0 | [16] |
| Debian / Ubuntu armhf | Fixed (trixie, 24.04) | i386 deliberately left at 32-bit [18][19][20]. |
| OpenBSD / NetBSD | Fixed in 2014 / 2012 | [3][11] |
| FreeBSD | Fixed except i386, which was retired in 15.0 | [21][22] |
| Windows / MSVC | Not affected by default | 64-bit time_t since VS2005. FILETIME is 64-bit [23][24]. |
| Android (32-bit) | Not fixed | Bionic keeps a 32-bit time_t on LP32 and has no plan to change [25]. |
| Embedded RTOS / toolchains | Mixed | Depends on vendor, C library and build configuration. See OS-Embedded-and-RTOS. |
The detailed matrix is on Operating-Systems.
Why it matters now: future dates
The rollover is about 11 years and 3 months away (4,108 days from 2026-10-21), but software meets 2038 long before the clock reaches it. Any calculation that projects into the future can cross the boundary today:
- Long timeouts and expiry dates. AOLserver failed in 2006 because "now + 1 billion seconds" passed 2038 [2]. Certificates, licences, tokens and cookies issued with very long lifetimes behave the same way. Oracle Access Manager hit a post-2038 cookie expiry in 2022 (secondary source) [2].
- Finance and insurance. A 30-year loan or bond issued in 2008 or later matures after January 2038.
- Scheduling, warranties, retention and compliance dates that are set 10–20 years ahead.
- Clock errors. A misbehaving NTP server or RTC can push a device's clock into 2037 or past 2038 without warning. In a 2024 report a private CA, fed bad time by a faulty NTP source, began issuing certificates "valid" from 2037 to 1910 [26].
- Long product lifecycles. Cars, PLCs, medical devices, meters, set-top boxes and routers sold in 2026 may well still be running in 2038. Many will never receive a firmware update. See Devices-and-Embedded-Systems and OS-Embedded-and-RTOS.
Affected versions / products
The per-OS pages carry the detailed tables:
| Area | Page |
|---|---|
| OS summary matrix | Operating-Systems |
| Linux kernel, glibc, musl, distributions | OS-Linux |
| BSDs and commercial Unix | OS-BSD-and-Unix |
| Windows | OS-Windows |
| macOS and iOS | OS-macOS-and-iOS |
| Android | OS-Android |
| RTOS and embedded Linux | OS-Embedded-and-RTOS |
| Languages | Programming-Languages |
| Devices | Devices-and-Embedded-Systems |
| Databases, file systems, formats | Databases, File-Systems, File-Formats-and-Protocols |
Risk & compliance notes
- What to inventory. Inventory every 32-bit OS image and binary, each C library and its version, every database column and file format that stores epoch seconds, and every device with a multi-decade service life. Use the Risk-Assessment-Checklist.
- Ownership. The OS vendor fixes the kernel and libc. You own application code, data formats, firmware you ship, and the third-party binaries you cannot rebuild.
- Timing. Failures involving future dates are happening already. Failures driven by the clock arrive on 2038-01-19. Devices sold today may still be in the field on that date.
- Lessons from Y2K. Early inventory, testing with clocks set forward, and supplier attestations proved effective in Y2K remediation. See Y2K-Lessons-for-2038 and Y2K-Remediation-and-Cost.
Detection & mitigation
- Check type widths:
sizeof(time_t)on every target, andgetconf LONG_BITon Linux. - Rebuild 32-bit Linux userland with
-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64(glibc ≥ 2.34, kernel ≥ 5.1/5.6), or move to musl ≥ 1.2. - Test with clocks set past 2038 (for example
faketime, or VMs and containers with a shifted clock) and with future-dated inputs. - Audit file systems (ext4 inode size, XFS
bigtime), database types and binary formats. - Full procedures are in Testing-and-Detection and Remediation-Guide. Real-world failures are collected in Known-2038-Incidents.
See also
- Operating-Systems · OS-Linux · OS-BSD-and-Unix · OS-Windows · OS-macOS-and-iOS · OS-Android · OS-Embedded-and-RTOS
- Programming-Languages · Lang-C-and-CPP · Lang-Java-and-JVM · Lang-DotNet · Lang-Python · Lang-PHP · Lang-JavaScript-and-TypeScript · Lang-Go-Rust-Swift · Lang-Perl-Ruby-and-Others
- Devices-and-Embedded-Systems · Devices-Industrial-and-Infrastructure · Devices-Automotive-Aviation-Medical · Devices-Networking-and-IoT
- Databases · File-Systems · File-Formats-and-Protocols
- Year-2000-Problem · Y2K-Timeline · Y2K-Remediation-and-Cost · Y2K-Incidents · Y2K-Lessons-for-2038
- Related-Date-Bugs · GPS-Week-Rollover · NTP-Era-2036 · Year-2106-and-Beyond
- Testing-and-Detection · Remediation-Guide · Risk-Assessment-Checklist · Known-2038-Incidents · Articles-and-Sources · Glossary
References
- Pondering 2038 — LWN.net (Jonathan Corbet), 2013-08-14. Linux options, the OpenBSD ABI break, and the embedded lifespan concern.
- Year 2038 problem — Wikipedia. Secondary overview: the AOLserver 2006 failure, the Oracle Access Manager 2022 cookie issue, and a solutions table.
- OpenBSD 5.5 release page — OpenBSD, 2014-05-01. "time_t is now 64 bits on all platforms". Unsigned 32-bit fields are "good till the year 2106".
- glibc NEWS file (mirror of sourceware glibc.git) — GNU C Library. 2.34:
_TIME_BITS=64, which requires LFS and kernel ≥ 5.1. 2.40:utmp/lastlogfields made unsigned (to 2106). - [GIT PULL] y2038: core, driver and file system changes — Arnd Bergmann, LKML, 2020-01-29. Linux 5.6 readiness, the 5.1 time64 syscalls,
input_eventmoved to unsigned, and remaining file systems. - What time is it? (QNX OS 8.0 Programmer's Guide) — BlackBerry QNX. Previous releases used unsigned 32-bit seconds; 8.0 uses signed 64-bit.
- Austin Group defect 1462: time_t width — Austin Group. Accepted requirement for a 64-bit
time_tin Issue 8. <sys/types.h>— POSIX.1-2024 (The Open Group Base Specifications Issue 8). "time_t shall be an integer type with a width … of at least 64 bits."- 32-bit 2038 issue — tz mailing list, November 1997. Early discussion of 2038 and LP64
time_t. - Re: time_t size: The year 2038 bug? — linux-kernel, 2000-01-05. The 2000 kernel thread on widening time fields.
- Announcing NetBSD 6.0 — The NetBSD Project, 2012. "time_t is now a 64-bit quantity on all NetBSD ports."
- Pondering 2038 — LWN.net, 2013-08-14. Reports Philip Guenther's OpenBSD 64-bit
time_tcommit of 2013-08-12. - Making inode time stamps y2038 ready (RFC 00/32) — Arnd Bergmann via LWN, 2014-05-30. The first Linux y2038 series.
- Solving the Year 2038 problem in the Linux kernel — Deepa Dinamani, opensource.com, 2019-01-21. VFS timestamp conversion merged in June 2018.
- y2038: add time64 syscalls — Arnd Bergmann via LWN, 2019-01-10. Syscall series for the 5.1 merge window.
- musl 1.2.0 released — musl mailing list (Openwall), 2020-02-20. "moves all 32-bit archs to 64-bit time_t".
- Microsoft Exchange year 2022 bug in FIP-FS breaks email delivery — BleepingComputer, 2022-01-01. Value 2,201,010,001 exceeded the signed int32 maximum.
- ReleaseGoals/64bit-time — Debian Wiki. Transition began 2024-02-27; i386 and hurd-i386 excluded.
- Ubuntu 24.04 LTS release notes — Canonical. "Ubuntu 24.04 LTS solves the Year 2038 problem that existed on armhf."
- Debian 13 "trixie" release notes §2.2.6 — Debian. "All architectures other than i386 now use a 64-bit time_t ABI." Released 2025-08-09 per Debian News.
- FreeBSD 15.0-RELEASE Release Notes — FreeBSD Project. i386, armv6 and 32-bit powerpc retired; armv7 remains.
- arch(7) — FreeBSD Manual Pages. "time_t is 8 bytes on all supported architectures except i386."
- time, _time32, _time64 — Microsoft Learn.
time_tis 64-bit by default._USE_32BIT_TIME_Tis discouraged and not allowed on 64-bit. - FILETIME structure — Microsoft Learn. 64-bit count of 100 ns intervals since 1601-01-01 UTC.
- 32-bit ABI bugs (bionic docs) — Android Open Source Project. "On 32-bit Android, time_t is 32-bit, which will overflow in 2038."
- IT incident report: VPN CA certificates dated 2037–1910 — The Register, 2024-02-09. A CA with 2037→1910 validity dates caused by 32-bit time and bad NTP.