fluttersmith/py-snippetsGitHub ↗

Whole months between two dates

Count complete calendar months between two dates, the way people count them.

Dates#calendarO(1) time✓ 4 examples pass on 3.11–3.14

From 15 January to 15 March is 2 months. From 31 January to 29 February isn’t a month yet.

months_diff.py✓ ruff · mypy --strict
from datetime import date


def months_diff(start: date, end: date) -> int:
    """Return the number of whole calendar months from ``start`` to ``end``."""
    months = (end.year - start.year) * 12 + (end.month - start.month)
    if months > 0 and end.day < start.day:
        months -= 1
    elif months < 0 and end.day > start.day:
        months += 1
    return months
  1. a month only counts once its day of the month comes round again
examples✓ 4 doctests · 3.11–3.14
passed on Python 3.11 to 3.14: >>> from datetime import datepassed on Python 3.11 to 3.14: >>> months_diff(date(2024, 1, 31), date(2024, 2, 29))0passed on Python 3.11 to 3.14: >>> months_diff(date(2024, 1, 15), date(2025, 3, 15))14passed on Python 3.11 to 3.14: >>> months_diff(date(2024, 3, 1), date(2024, 1, 1))-2
Edit the function or the examples and run the doctests here, on Python 3.14. Python loads only when you click (about 7 MB, cached after the first time).

How it works

  • Year and month differences give a first count.
  • If the end’s day of the month hasn’t reached the start’s, the last month isn’t complete.
  • It works backwards too, returning a negative count.

Complexity: O(1) time and space

Importfrom pysnippets.dates.months_diff import months_diffNo dependencies: copy months_diff.py into your project, or clone the repo.

Adapted from months-diff in 30-seconds-of-python by the 30 seconds of code contributors, CC BY 4.0. Changed: Rewritten to count calendar months, not 30-day blocks. Suggest an edit.