Windows
In brief: Windows itself does not count time the Unix way. Its native clock is a 64-bit count of 100-nanosecond steps since 1601, which will not overflow for tens of thousands of years. Microsoft's C compiler has also used 64-bit
time_tby default since Visual Studio 2005. Problems on Windows come from programs that deliberately chose 32-bit time, from old file formats and network structures, and from third-party code that stores dates in 32-bit integers. Microsoft's own "Y2K22" Exchange outage in 2022 shows how that last category fails.
| Risk level | Low (OS) · Medium (legacy applications, formats and third-party code) |
| Status | OS time APIs not affected. MSVC CRT time_t 64-bit by default since VS2005. Legacy 32-bit uses remain in applications and formats |
| Last reviewed | 2026-10-21 |
2038 status at a glance
- At risk ConfirmedWindows programs built with Visual Studio 2003 or earlier, or with _USE_32BIT_TIME_TThese use the old 32-bit time_t. Microsoft warns such programs "may fail after January 18, 2038".Do: Rebuild with a current compiler and remove _USE_32BIT_TIME_T.
Not affected or different deadline (2), and why
- Not affectedPrograms built with Visual Studio 2005 or later (default settings)In the modern CRT, time_t is 64-bit by default and valid to 3000-12-31.
- Not affectedWindows NT kernel, NTFS and Win32 time APIs (FILETIME, SYSTEMTIME)Windows stores time as a 64-bit count of 100-nanosecond intervals since 1601, which lasts to about the year 30,828.
Overview
Windows NT and its successors keep system time as FILETIME: "a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC)" [1]. The core Win32 time APIs use this representation or the SYSTEMTIME calendar struct, among them GetSystemTimeAsFileTime, GetFileTime/SetFileTime and FileTimeToSystemTime. NTFS stores file timestamps in the same format, in UTC [1]. A 64-bit count of 100 ns ticks lasts until roughly the year 30,828, so the Windows kernel and file system are not affected by 2038 [2].
The 2038 problem reaches Windows through the C runtime library (CRT), which provides the POSIX-style time_t, time(), localtime() and so on, and through any software that copied the Unix convention.
Technical details
The MSVC CRT and time_t
- Microsoft's documentation: "
time_t… is equivalent to__time64_tby default, which is a 64-bit signed integer that supports dates through 23:59:59, December 31, 3000 UTC" [3]. The CRT deliberately caps dates at the year 3000, far beyond the theoretical 64-bit range. _USE_32BIT_TIME_T: "If you need the compiler to interprettime_tas the old 32-bittime_t, define_USE_32BIT_TIME_T. We don't recommend_USE_32BIT_TIME_Tbecause your application may fail after January 18, 2038. This macro isn't allowed on 64-bit platforms." [3] The documentation says January 18, presumably because of local time zones west of UTC. The UTC limit is 2038-01-19 03:14:07.- Explicit 32-bit functions remain available and are 2038-limited regardless of settings:
_time32,_mktime32,_gmtime32,_localtime32,_ctime32,_utime32,_stat32,_findfirst32and others [3]. - History: 64-bit
time_tbecame the default in Visual C++ 2005 (VC 8.0 / msvcr80.dll). Before that,time_twas a 32-bitlong. The change was a documented breaking change that caused binary incompatibilities with projects that sharedtime_t-containing structs across DLLs built with different compilers. Python's build is one example [4], and MySQL bug #39802 is another [5]. - MinGW / MinGW-w64 follow the MSVC CRT conventions, and
_USE_32BIT_TIME_Taffects them too. Older MinGW toolchains and code linked against the legacymsvcrt.dllshould be checked individually [6].
Places where 32-bit time is still used on Windows
| Location | Representation | Limit | Notes |
|---|---|---|---|
Code compiled with _USE_32BIT_TIME_T (32-bit targets only) |
32-bit signed time_t |
2038-01-19 | Discouraged by Microsoft [3] |
_time32, _mktime32, _stat32, __time32_t fields |
32-bit signed | 2038-01-19 | Explicit opt-in [3] |
PE/COFF TimeDateStamp in every EXE/DLL/OBJ |
"The low 32 bits of the number of seconds since 00:00 January 1, 1970 (a C run-time time_t value)" | 2038 if read as signed, 2106 as unsigned | Many PE parsing and forensic tools treat it as signed. Reproducible builds store a hash here, not a time [7] |
Winsock struct timeval |
long tv_sec; long tv_usec;, and long is 32-bit on Windows even on x64 |
Used for intervals (for example the select timeout), so 2038 is not a direct problem |
Portable code that puts absolute epoch time into a timeval on Windows truncates it [8] |
| FAT/exFAT timestamps | Year stored as an offset from 1980 in 7 bits | 2107 | "the year 1980 with the value 0 and the year 2107 with the value 127" [9] |
| Third-party formats and databases | Varies | Varies | See File-Formats-and-Protocols and Databases |
Application code storing dates in int/DWORD/LONG |
32-bit | Varies | The Y2K22 class of bugs (below) |
Other runtimes on Windows (.NET DateTime, Java, Python and others) have their own representations. See Lang-DotNet and Programming-Languages.
Contrast: the Exchange "Y2K22" bug (2022-01-01)
On 2022-01-01 at 00:00 UTC, on-premises Exchange Server 2016 and 2019 stopped delivering mail. The FIP-FS anti-malware engine loaded signature updates whose version string encoded the date as YYMMDDHHMM. The first update of 2022 had the version 2201010001. Exchange parsed that into a signed 32-bit integer, whose maximum is 2,147,483,647, so the conversion failed with event ID 1106: "Can't convert "2201010001" to long." The scan engine did not load and messages piled up in transport queues [10]. Microsoft said it was "not an issue with malware scanning or the malware engine, and it is not a security-related issue" and released a fix that admins could apply manually or with an automated PowerShell script [11]. Until it was applied, the common stopgap was to disable FIP-FS scanning, which left mail unscanned [10].
The bug is not a time_t overflow. It is the same class of failure, though: a date squeezed into a signed 32-bit integer, failing on a predictable date that nobody tested. The same YYMMDDHHMM scheme would have hit the limit at 2021-12-31 23:59, just as an epoch-seconds value hits it at 2038-01-19. Testing with clocks and data set forward would have caught it. See Related-Date-Bugs and Known-2038-Incidents.
Affected versions / products
| Product | Status |
|---|---|
Windows NT kernel, NTFS, Win32 FILETIME/SYSTEMTIME APIs |
Not affected (to ~30,828) [1][2] |
| MSVC CRT ≥ VS2005 (msvcr80 → UCRT), default build | time_t 64-bit; safe to 3000-12-31 [3] |
| MSVC CRT ≤ VS2003 (msvcr71 and earlier) | 32-bit time_t — affected [4] |
Any 32-bit binary built with _USE_32BIT_TIME_T |
Affected [3] |
Code using _time32/__time32_t or storing time_t in long/int |
Affected |
| FAT32/exFAT volumes | Limited to 2107 [9] |
| Exchange 2016/2019 FIP-FS (before the January 2022 fix) | Y2K22 failure [10] |
Risk & compliance notes
- The main Windows risk lies in line-of-business applications built before 2005 or ported from Unix, and in embedded Windows systems (kiosks, HMIs, medical carts) that run old 32-bit code. See Devices-Industrial-and-Infrastructure.
- Interop is a hazard. A DLL built with a 32-bit
time_tthat passes a struct to an EXE built with a 64-bittime_tcorrupts data [4][5]. - Inventory: search source for
_USE_32BIT_TIME_T,_time32,__time32_t, and casts oftime_ttoint/long/DWORD.
Detection & mitigation
# find the legacy macro and explicit 32-bit time functions in a source tree
Select-String -Path .\src\* -Recurse -Pattern '_USE_32BIT_TIME_T|_time32|__time32_t|_mktime32|_gmtime32'
- Rebuild with a current MSVC and remove
_USE_32BIT_TIME_T. Prefer 64-bit targets, where the macro is rejected. - Use
FILETIME/SYSTEMTIMEorstd::chronofor new Windows code. - Test with the clock set past 2038-01-19 in a VM, and with future-dated data such as certificates, licence expiries and schedules.
- See Testing-and-Detection and Remediation-Guide.
See also
- Year-2038-Problem · Operating-Systems · Lang-C-and-CPP · Lang-DotNet
- File-Systems · File-Formats-and-Protocols
- Related-Date-Bugs · Known-2038-Incidents
References
- FILETIME structure (minwinbase.h) — Microsoft Learn. 64-bit count of 100 ns intervals since 1601-01-01 UTC. NTFS stores UTC.
- Year 2038 problem — Wikipedia. Secondary source: the Windows API is unaffected until about the year 30,828. VC++ 64-bit
time_tsince 2005. - time, _time32, _time64 — Microsoft Learn (C runtime reference). Default 64-bit, year-3000 limit,
_USE_32BIT_TIME_Tguidance. - [Patches] python-Patches-1437769: Size of time_t changed to 64 bits in MSVC++ 2005 CRT — python.org mailing list, 2006-03. Quotes Microsoft's VS2005 breaking-change note (seen in search results).
- Bug #39802: On Windows, 32-bit time_t should be enforced — MySQL Bugs. Binary incompatibility caused by the VS2005 change (seen in search results).
- MinGW ticket #37938 — OSDN.
_USE_32BIT_TIME_Thandling in MinGW (seen in search results). - PE Format — Microsoft Learn. COFF header
TimeDateStamp: "The low 32 bits of the number of seconds since 00:00 January 1, 1970". - TIMEVAL structure (winsock.h) — Microsoft Learn.
long tv_sec; long tv_usec;, used to specify a time interval. - exFAT file system specification §7.4.8.6 — Microsoft Learn. Year field covers 1980–2107.
- Microsoft Exchange year 2022 bug in FIP-FS breaks email delivery — BleepingComputer, 2022-01-01. Value 2,201,010,001 versus the signed int32 maximum; Microsoft statement.
- Microsoft releases fix for disruptive Exchange Y2K22 bug — Computing, 2022-01. Fix released as a script (seen in search results).