Skip to content

BUG: date_range not excluding dates correctly with periods and inclusive not 'both' #46771

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
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
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.5.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ Datetimelike
- Bug in :meth:`Index.astype` when casting from object dtype to ``timedelta64[ns]`` dtype incorrectly casting ``np.datetime64("NaT")`` values to ``np.timedelta64("NaT")`` instead of raising (:issue:`45722`)
- Bug in :meth:`SeriesGroupBy.value_counts` index when passing categorical column (:issue:`44324`)
- Bug in :meth:`DatetimeIndex.tz_localize` localizing to UTC failing to make a copy of the underlying data (:issue:`46460`)
- Bug in :meth:`date_range` when ``start`` or ``end`` was not specified, failed to exclude first or last date despite ``inclusive`` not being ``"both"`` (:issue:`46331`)
-

Timedelta
Expand Down
16 changes: 10 additions & 6 deletions pandas/core/arrays/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,17 +484,21 @@ def _generate_range(
# to overflow and cast to e.g. f8, but if it does we need to cast
i8values = i8values.astype("i8")

# Apply `inclusive` rules
if start == end:
# Particular case where we act iff `inclusive="neither"`
# cf. GH #43394
if not left_inclusive and not right_inclusive:
i8values = i8values[1:-1]
else:
elif len(i8values):
start_i8 = Timestamp(start).value
end_i8 = Timestamp(end).value
if not left_inclusive or not right_inclusive:
if not left_inclusive and len(i8values) and i8values[0] == start_i8:
i8values = i8values[1:]
if not right_inclusive and len(i8values) and i8values[-1] == end_i8:
i8values = i8values[:-1]
_left, _right = None, None
if not left_inclusive and (i8values[0] == start_i8 or start is None):
_left = 1
if not right_inclusive and (i8values[-1] == end_i8 or end is None):
_right = -1
i8values = i8values[_left:_right]

dt64_values = i8values.view("datetime64[ns]")
dtype = tz_to_dtype(tz)
Expand Down
28 changes: 28 additions & 0 deletions pandas/tests/indexes/datetimes/test_date_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,34 @@ def test_range_where_start_equal_end(self, inclusive_endpoints_fixture):

tm.assert_index_equal(result, expected)

def test_range_without_start_inclusive(self, inclusive_endpoints_fixture):
# GH 46331
start = Timestamp("2000-01-01")
end = Timestamp("2000-01-04")
both_range = date_range(start, end, inclusive="both")

result = date_range(end=end, periods=4, inclusive=inclusive_endpoints_fixture)
expected = _get_expected_range(
start, end, both_range, inclusive_endpoints_fixture
)

tm.assert_index_equal(result, expected)

def test_range_without_end_inclusive(self, inclusive_endpoints_fixture):
# GH 46331
start = Timestamp("2000-01-01")
end = Timestamp("2000-01-04")
both_range = date_range(start, end, inclusive="both")

result = date_range(
start=start, periods=4, inclusive=inclusive_endpoints_fixture
)
expected = _get_expected_range(
start, end, both_range, inclusive_endpoints_fixture
)

tm.assert_index_equal(result, expected)


class TestDateRangeTZ:
"""Tests for date_range with timezones"""
Expand Down