Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions rust/src/python/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,14 +341,16 @@ pub fn precise_diff<'py>(
day_diff += days_in_last_month;
}
}
Ordering::Equal => {
Ordering::Equal
if dtinfo1.day == days_in_last_month && dtinfo2.day == days_in_month =>
{
// We have exactly a full month
// We remove the days difference
// and add one to the months difference
day_diff = 0;
month_diff += 1;
}
Ordering::Greater => {
Ordering::Equal | Ordering::Greater => {
// We have a full month
day_diff += days_in_last_month;
}
Expand Down
6 changes: 5 additions & 1 deletion src/pendulum/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,11 @@ def precise_diff(
d_diff += d1.day
else:
d_diff += days_in_last_month
elif d_diff == days_in_month - days_in_last_month:
elif (
d_diff == days_in_month - days_in_last_month
and d1.day == days_in_last_month
and d2.day == days_in_month
):
# We have exactly a full month
# We remove the days difference
# and add one to the months difference
Expand Down
4 changes: 2 additions & 2 deletions tests/date/test_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ def test_diff_for_humans_other_and_month():

assert today.diff_for_humans(today.add(months=1)) == "1 month before"

with pendulum.travel_to(pendulum.datetime(2017, 1, 31)):
with pendulum.travel_to(pendulum.datetime(2017, 1, 31, tz="America/Toronto")):
today = pendulum.today().date()

assert today.diff_for_humans(today.add(weeks=4)) == "1 month before"
Expand Down Expand Up @@ -314,7 +314,7 @@ def test_diff_for_humans_other_and_future_month():
assert today.diff_for_humans(today.subtract(weeks=4)) == "4 weeks after"
assert today.diff_for_humans(today.subtract(months=1)) == "1 month after"

with pendulum.travel_to(pendulum.datetime(2017, 2, 28)):
with pendulum.travel_to(pendulum.datetime(2017, 2, 28, tz="America/Toronto")):
today = pendulum.today().date()

assert today.diff_for_humans(today.subtract(weeks=4)) == "1 month after"
Expand Down
38 changes: 38 additions & 0 deletions tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,44 @@ def test_precise_diff_timezone() -> None:
assert diff.total_days == 0


@pytest.mark.parametrize(
"year, start_day, expected_days", [(2023, 4, 28), (2024, 3, 29)]
)
@pytest.mark.parametrize("reverse", [False, True])
def test_precise_diff_partial_month(
year: int, start_day: int, expected_days: int, reverse: bool
) -> None:
start = datetime(year, 1, start_day)
end = datetime(year, 2, 1)
sign = -1 if reverse else 1
diff = precise_diff(end, start) if reverse else precise_diff(start, end)

assert_diff(diff, days=sign * expected_days)

start = pendulum.datetime(year, 1, start_day, tz="America/Toronto")
end = pendulum.datetime(year, 2, 1, tz="America/Toronto")
interval = start - end if reverse else end - start

assert interval.in_months() == 0
assert interval.in_days() == sign * expected_days


@pytest.mark.parametrize("year, end_day", [(2023, 28), (2024, 29)])
def test_precise_diff_clipped_full_month(year: int, end_day: int) -> None:
start = datetime(year, 1, 31)
end = datetime(year, 2, end_day)

assert_diff(precise_diff(start, end), months=1)
assert_diff(precise_diff(end, start), months=-1)


def test_precise_diff_partial_month_with_borrowed_day() -> None:
start = datetime(2024, 1, 30, 1)
end = datetime(2024, 2, 29)

assert_diff(precise_diff(start, end), days=29, hours=23)


def test_week_day() -> None:
assert week_day(2017, 6, 2) == 5
assert week_day(2017, 1, 1) == 7
Expand Down