Leap year problem


The leap year problem is a problem for both digital and non-digital documentation and data storage situations which results from the wrong calculation of which years are leap years, or from manipulating dates without regard to the difference between leap years and common years.

Categories

Leap year bugs typically fall into two impact categories:
  1. Those that lead to error conditions, such as exceptions, error return codes, uninitialized variables, or endless loops
  2. Those that lead to incorrect data, such as off-by-one problems in range queries or aggregation

    Examples

Python

The following Python code is an example of a Category 1 leap year bug. It will work properly until today becomes February 29. Then, it will attempt to create a February 29 of a common year, which does not exist. The date constructor will raise a ValueError with the message "day is out of range for month".

from datetime import date
today = date.today
later = today.replace

Windows C++

The following Windows C++ code is an example of a Category 1 leap year bug. It will work properly until st becomes February 29. Then, it will attempt to create a February 29 of a common year, which does not exist. Passing this to any function that accepts a SYSTEMTIME struct will likely fail.
For example, the SystemTimeToFileTime call shown here will return an error code. Since that return value is unchecked, this will result in ft being left uninitialized.

SYSTEMTIME st;
FILETIME ft;
GetSystemTime;
st.wYear++;
SystemTimeToFileTime;

C#

The following.NET C# code is an example of a Category 1 leap year bug. It will work properly until dt becomes February 29. Then, it will attempt to create a February 29 of a common year, which does not exist. The DateTime constructor will throw an ArgumentOutOfRangeException.

DateTime dt = DateTime.Now;
DateTime result = new DateTime;

JavaScript

The following JavaScript code is an example of a Category 2 leap year bug. It will work properly until dt becomes February 29, such as on 2020-02-29. Then it will attempt to set the year to 2021. Since 2021-02-29 doesn't exist, the Date object will roll forward to the next valid date, which is 2021-03-01.

var dt = new Date;
dt.setFullYear;

Bad leap year algorithm (many languages)

The following code is an example of a leap year bug that is seen in many languages. It may cause either a Category 1 or Category 2 impact, depending on what the result is used for. It incorrectly assumes that a leap year occurs exactly every four years.

bool isLeapYear = year % 4 0;

The correct leap year algorithm is explained at Leap Year Algorithm.

Occurrences

There have been many occurrences of leap year bugs: