From 30249505267d676767777f033f930184d291e282 Mon Sep 17 00:00:00 2001 From: Ryan Kendra Date: Thu, 5 Dec 2024 17:09:05 -0500 Subject: [PATCH] Fixed span_range omitting dates when frame is 'month', exact is True, and start.day is 31 (#1185) --- arrow/arrow.py | 10 ++++++++++ tests/test_arrow.py | 16 +++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/arrow/arrow.py b/arrow/arrow.py index 9d1f5e30..8fbc1e76 100644 --- a/arrow/arrow.py +++ b/arrow/arrow.py @@ -699,7 +699,17 @@ def span_range( yield r.span(frame, bounds=bounds, exact=exact) for r in _range: + day_is_clipped = False floor, ceil = r.span(frame, bounds=bounds, exact=exact) + next = ceil.shift(microseconds=+1) + if frame == "month" and next.day < start.day: + day_is_clipped = True + if day_is_clipped and not next._is_last_day_of_month(next): + days_to_shift = ( + min(start.day, calendar.monthrange(next.year, next.month)[1]) + - next.day + ) + ceil = ceil.shift(days=days_to_shift) if ceil > end: ceil = end if bounds[1] == ")": diff --git a/tests/test_arrow.py b/tests/test_arrow.py index 086f5cf2..caaf9e51 100644 --- a/tests/test_arrow.py +++ b/tests/test_arrow.py @@ -1185,7 +1185,7 @@ def test_month(self): (arrow.Arrow(2013, 4, 1), arrow.Arrow(2013, 4, 30, 23, 59, 59, 999999)), ] - def test_month_end(self): + def test_month_exact(self): result = list( arrow.Arrow.span_range( "month", datetime(2013, 1, 31), datetime(2014, 1, 31), exact=True @@ -1207,6 +1207,20 @@ def test_month_end(self): (arrow.Arrow(2013, 12, 31), arrow.Arrow(2014, 1, 30, 23, 59, 59, 999999)), ] + def test_month_exact_leap(self): + result = list( + arrow.Arrow.span_range( + "month", datetime(2012, 1, 31), datetime(2012, 5, 31), exact=True + ) + ) + + assert result == [ + (arrow.Arrow(2012, 1, 31), arrow.Arrow(2012, 2, 28, 23, 59, 59, 999999)), + (arrow.Arrow(2012, 2, 29), arrow.Arrow(2012, 3, 30, 23, 59, 59, 999999)), + (arrow.Arrow(2012, 3, 31), arrow.Arrow(2012, 4, 29, 23, 59, 59, 999999)), + (arrow.Arrow(2012, 4, 30), arrow.Arrow(2012, 5, 30, 23, 59, 59, 999999)), + ] + def test_week(self): result = list( arrow.Arrow.span_range("week", datetime(2013, 2, 2), datetime(2013, 2, 28))