Skip to content

Commit 40c3159

Browse files
jbrockmendelclaude
andauthored
BUG: fix date_range inclusive filtering with periods (#64788)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d1debc7 commit 40c3159

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed

doc/source/whatsnew/v3.1.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ Datetimelike
160160
^^^^^^^^^^^^
161161
- Bug in :class:`Timestamp` constructor where passing ``np.str_`` objects would fail in Cython string parsing (:issue:`48974`)
162162
- Bug in :class:`Timestamp` constructor, :class:`Timedelta` constructor, :func:`to_datetime`, and :func:`to_timedelta` with non-round ``float`` input and ``unit`` failing to raise when the value is just outside the representable bounds (:issue:`57366`)
163+
- Bug in :func:`date_range` where ``inclusive`` parameter failed to filter endpoints when only ``start`` and ``periods`` or ``end`` and ``periods`` were specified (:issue:`46331`)
163164
- Bug in :func:`to_datetime` and :func:`to_timedelta` on ARM platforms where round ``float`` values outside the int64 domain (e.g. ``float(2**63)``) could silently produce incorrect results instead of raising (:issue:`64619`)
164165
- Bug in :func:`to_datetime` and :func:`to_timedelta` where ``uint64`` values greater than ``int64`` max silently overflowed instead of raising :class:`OutOfBoundsDatetime` or :class:`OutOfBoundsTimedelta` (:issue:`60677`)
165166
- Bug in :meth:`DatetimeArray.isin` and :meth:`TimedeltaArray.isin` where mismatched resolutions could silently truncate finer-resolution values, leading to false matches (:issue:`64545`)

pandas/core/arrays/datetimes.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -551,8 +551,20 @@ def _generate_range(
551551
if not left_inclusive and not right_inclusive:
552552
i8values = i8values[1:-1]
553553
else:
554-
start_i8 = Timestamp(start)._value
555-
end_i8 = Timestamp(end)._value
554+
start_i8 = (
555+
Timestamp(start)._value
556+
if start is not None
557+
else i8values[0]
558+
if len(i8values)
559+
else 0
560+
)
561+
end_i8 = (
562+
Timestamp(end)._value
563+
if end is not None
564+
else i8values[-1]
565+
if len(i8values)
566+
else 0
567+
)
556568
if not left_inclusive or not right_inclusive:
557569
if not left_inclusive and len(i8values) and i8values[0] == start_i8:
558570
i8values = i8values[1:]

pandas/tests/indexes/datetimes/test_date_range.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,38 @@ def test_range_where_start_equal_end(self, inclusive_endpoints_fixture):
743743

744744
tm.assert_index_equal(result, expected)
745745

746+
@pytest.mark.parametrize(
747+
"inclusive, expected_values",
748+
[
749+
("both", ["2020-06-01", "2020-06-02", "2020-06-03", "2020-06-04"]),
750+
("left", ["2020-06-01", "2020-06-02", "2020-06-03"]),
751+
("right", ["2020-06-02", "2020-06-03", "2020-06-04"]),
752+
("neither", ["2020-06-02", "2020-06-03"]),
753+
],
754+
)
755+
def test_inclusive_with_periods_and_start(self, inclusive, expected_values):
756+
# GH#46331 - inclusive should filter endpoints even when
757+
# only start+periods is provided (end is not specified)
758+
result = date_range(start="2020-06-01", periods=4, inclusive=inclusive)
759+
expected = DatetimeIndex(expected_values, freq="D")
760+
tm.assert_index_equal(result, expected)
761+
762+
@pytest.mark.parametrize(
763+
"inclusive, expected_values",
764+
[
765+
("both", ["2020-06-01", "2020-06-02", "2020-06-03", "2020-06-04"]),
766+
("left", ["2020-06-01", "2020-06-02", "2020-06-03"]),
767+
("right", ["2020-06-02", "2020-06-03", "2020-06-04"]),
768+
("neither", ["2020-06-02", "2020-06-03"]),
769+
],
770+
)
771+
def test_inclusive_with_periods_and_end(self, inclusive, expected_values):
772+
# GH#46331 - inclusive should filter endpoints even when
773+
# only end+periods is provided (start is not specified)
774+
result = date_range(end="2020-06-04", periods=4, inclusive=inclusive)
775+
expected = DatetimeIndex(expected_values, freq="D")
776+
tm.assert_index_equal(result, expected)
777+
746778
def test_freq_dateoffset_with_relateivedelta_nanos(self):
747779
# GH 46877
748780
freq = DateOffset(hours=10, days=57, nanoseconds=3)

0 commit comments

Comments
 (0)