The bug
Open Excel. In any cell, type =DATE(1900,2,29). Press Enter. Excel happily displays "2/29/1900" or "29-Feb-1900" depending on your locale.
February 29, 1900 didn't exist. 1900 wasn't a leap year. By the Gregorian rule, century years (those divisible by 100) are not leap years — unless they're also divisible by 400. 1900 is divisible by 100 and not by 400. So it's not a leap year. February in 1900 had 28 days, the same as in 1901, 1902, 1903.
Excel doesn't know this. As far as Excel is concerned, February 29, 1900 is a valid date. So is March 1, March 2, and every date after — but each one is off by a day from reality.
This is on purpose
Microsoft knows. They've known for at least 30 years. The bug is intentional.
The reason goes back to Lotus 1-2-3, which dominated spreadsheets in the early 1980s and which had this same bug. When Microsoft built Excel for Macintosh in 1985 and then Excel for Windows in 1987, they wanted Lotus 1-2-3 users to be able to import their files into Excel with date columns intact. The 1900 leap year bug was already baked into Lotus 1-2-3's date serial system. To match it exactly, Microsoft built the same bug into Excel.
40 years later, the bug is still there. Microsoft has explained their reasoning in the official Microsoft Support article "Excel incorrectly assumes that the year 1900 is a leap year" — which has been updated several times but still concludes that fixing the bug would break decades of compatibility with existing spreadsheets, and is therefore not worth the cost.
What this means for serial dates
Excel stores dates internally as serial numbers. The value 1 represents January 1, 1900. The value 2 represents January 2. And so on.
Because of the bug, 60 represents February 29, 1900 (which didn't exist). After that point, every serial number is off by one from a correct calendar. 61 is March 1, 1900 — which is correctly the 61st day of 1900 only because the phantom February 29 makes the math line up.
The practical implications:
- For any date from March 1, 1900 onward — which is essentially every date you'll ever work with — the Excel serial number is exactly 1 too high compared to what a correct calendar would say.
- For dates before March 1, 1900, Excel's serial numbers are correct.
- The Unix-epoch offset used to convert Excel serials to Unix seconds is
25569, which is the count of days from Excel's epoch (December 30, 1899, accounting for the phantom day) to January 1, 1970.
The 1904 system: a parallel timeline
Excel for Macintosh originally shipped with a different date system: days since 1904-01-01. No phantom leap day. No off-by-one bug. This is called the "1904 date system" and it's still selectable in modern Excel via File → Options → Advanced → "Use 1904 date system."
If you encounter a workbook that shows dates 4 years and 1 day off from what you expected, it's probably using the 1904 system. The offset between the two systems is exactly 1462 days.
The 1904 system has its own problems: dates before 1904 can't be represented. But it has the appealing property of correct calendar arithmetic.
What this means for your code
If you're parsing Excel files programmatically (via openpyxl, ExcelJS, pandas, etc.), the libraries handle the 1900 leap year bug for you. They use the same formula Excel does, which produces correct dates for everything past March 1, 1900.
Where this trips people up is when they implement Excel date parsing themselves — say, processing a CSV export that has serial numbers — and use a naive "days since 1900-01-01" formula. They get a date one day off. The fix is either to use one of the well-tested libraries, or to use the same compensation Excel does (treat the epoch as 1899-12-30 instead of 1900-01-01).
For interactive conversion, the Excel OADate converter on epochtime.tools handles this correctly — the formula it uses is unix_sec = (excel_serial - 25569) × 86400, which already includes the offset compensation.
The Lotus origin
So how did the bug get into Lotus 1-2-3 in the first place? The official Lotus team explanation has been lost to time, but the most plausible theory is that the developers used a simpler algorithm: "every year divisible by 4 is a leap year." This is correct for the Julian calendar and approximately correct for the Gregorian calendar — the century-rule exception only matters for years divisible by 100, which most code never has to handle. They got away with it for years before anyone noticed.
By the time anyone wanted to fix it, the bug had been preserved in tens of thousands of customer spreadsheets, and changing it would have broken compatibility. Same pattern as Microsoft's later decision: the bug becomes the standard, and the standard outlives the original software.
Other "wrong leap year" stories
Excel isn't alone here. Several other systems have had quietly-wrong leap year handling:
- Microsoft Zune music player (2008): first-generation Zunes froze on December 31, 2008, because the firmware had a leap year handling bug for 2008.
- Sony PlayStation 3 (2010): on March 1, 2010, all PS3 consoles incorrectly assumed it was February 29 (treating 2010 as a leap year). Online services broke.
- Microsoft Azure (2012): a service-wide outage on February 29, 2012 was caused by leap-year bugs in cert validation code.
- iOS Photos (2016): a bug in photo timestamp display made some photos appear with future dates after February 29, 2016.
The lesson: leap year math seems trivial. It's not. The "divisible by 4" rule is right 75% of the time, "divisible by 4 except 100" is right 99% of the time, "divisible by 4 except 100 except 400" is the actual rule. Most code uses one of the first two and gets lucky for decades.
The takeaway
- Excel will still tell you February 29, 1900 was a real day. It wasn't.
- This bug is preserved deliberately for backwards compatibility, and won't be fixed.
- For modern dates (anything past March 1900), the practical impact is just a +1 offset in serial numbers, which all standard libraries already account for.
- If you implement Excel date parsing yourself, use the epoch
1899-12-30, not1900-01-01— the difference handles the phantom day correctly. - If you see a 4-year discrepancy in a workbook, suspect the 1904 date system.
For interactive conversion you can spot-check with the Excel OADate converter.
Published April 21, 2026. Tagged: excel, history, bugs.