Relativedelta seems to be sometimes buggy when counting days / or / month
12:07 08 Dec 2025

This is a pretty straightforward code which uses relativedelta.

from datetime import date, timedelta

from dateutil.relativedelta import relativedelta


def _(message: str) -> str:
    """Fake translation function."""
    return message


def get_my_tuple(
    d1: date | str,
    d2: date | str,
    include_start: bool = True,
    include_end: bool = True,
):
    if isinstance(d1, str):
        d1 = date.fromisoformat(d1)
    if isinstance(d2, str):
        d2 = date.fromisoformat(d2)

    if d2 < d1:
        d1, d2 = d2, d1

    if not include_start:
        d1 = d1 + timedelta(days=1)
    if include_end:
        d2 = d2 + timedelta(days=1)

    if d1.year == d2.year and d1.month == d2.month:
        days = abs(d2.day - d1.day)
        return "{} {}".format(days, _("[days]") if days > 1 else _("[day]"))

    result = []
    r = relativedelta(d2, d1)
    if r.years:
        result.append(
            "{} {}".format(r.years, _("[years]") if r.years > 1 else _("[year]"))
        )
    if r.months:
        result.append(
            "{} {}".format(r.months, _("[months]") if r.months > 1 else _("[month]"))
        )
    if r.days:
        result.append(
            "{} {}".format(r.days, _("[days]") if r.days > 1 else _("[day]"))
        )
    if len(result) > 1:
        result[-2] = "{} {} {}".format(result[-2], _("[and]"), result[-1])
        result.pop()
    return ", ".join(result)

When I run my own test, passing some dates, I get something not normal:

    test_case("-", "2025-11-23", "2025-12-31")

    23/11/2025 -> 31/12/2025: 1 [month] [and] 9 [days]

Whereas it should be 1 [month] [and] 8 [days]!

This is correct: 23/11/2025 -> 21/12/2025: 29 [days] And add one day, it's not correct: 23/11/2025 -> 22/12/2025: 1 [month] It should be 30 [days] and only start counting 1 [month] later

What am I doing wrong?

python relativedelta humanize