Skip to content

Instantly share code, notes, and snippets.

@rayluo
Last active February 6, 2020 19:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rayluo/e0c57d8e720f1bb5983ace1e50dbdfcf to your computer and use it in GitHub Desktop.
Save rayluo/e0c57d8e720f1bb5983ace1e50dbdfcf to your computer and use it in GitHub Desktop.
Possible Leap Year Bugs in Your Python Code

Possible Leap Year Bugs in Your Python Code

Author: Ray Luo
Date: 2020-2-6
    Know your enemy.
               - Sun Tzu

This is a Python code snippet to demonstrate how some possible leap-year bugs could happen in your Python code base.

With such understanding, you are better educated to know what to look for in your code base.

# Experiencing all the leap year anti-patterns defined in
# https://dev.azure.com/msazure/AzureWiki/_wiki/wikis/AzureWiki.wiki/14194/Leap-Year-Code-Anti-patterns
from datetime import date, datetime
from datetime import timedelta
# Anti-pattern 1: Adding/subtracting/modifying year while keeping the existing month and day
leapday2020 = date(2020, 2, 29)
# leapday2020.replace(year=2019) # It raises ValueError
# Anti-pattern 1a, 6: Assuming all combinatinos of year-month-day components are valid
# nonexist = date(2019, 2, 29) # It raises ValueError
# Anti-pattern 2: Adding or subtracting days when intending to represent a year
first_day_2020 = date(2020, 1, 1)
next_year = first_day_2020 + timedelta(days=365)
print(next_year.year) # It will not be 2021
# Solution
real_next_year = first_day_2020.replace(year=first_day_2020.year + 1)
print(real_next_year.year) # It will be 2021
# Anti-pattern 3: Behavior and solution similar to Anti-pattern 2
# Anti-pattern 4:
days = [0] * 365
print(len(days)) # Insufficient to store daily data sample in a leap year
# Anti-pattern 5, 7: Detect leap year incorrectly
year = 1900
is_leap_year = year % 4 == 0 # This is True
if is_leap_year:
print("Is year 1900 really a leap year?")
# date(year, 2, 29) # 1900 is not a leap year
# Anti-pattern 8: Parsing a date string containing only month and day information
print(datetime.strptime("2-28", "%m-%d")) # Year defaults to 1900, so got 1900-2-28
# print(datetime.strptime("2-29", "%m-%d")) # ValueError
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment