Skip to content

BUG: DatetimeIndex.intersection losing freq and tz #33604

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

Merged
merged 2 commits into from
Apr 17, 2020
Merged
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.1.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ Datetimelike
- Bug in :class:`Timestamp` arithmetic when adding or subtracting a ``np.ndarray`` with ``timedelta64`` dtype (:issue:`33296`)
- Bug in :meth:`DatetimeIndex.to_period` not infering the frequency when called with no arguments (:issue:`33358`)
- Bug in :meth:`DatetimeIndex.tz_localize` incorrectly retaining ``freq`` in some cases where the original freq is no longer valid (:issue:`30511`)
- Bug in :meth:`DatetimeIndex.intersection` losing ``freq`` and timezone in some cases (:issue:`33604`)

Timedelta
^^^^^^^^^
Expand Down
4 changes: 2 additions & 2 deletions pandas/core/indexes/datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -724,10 +724,10 @@ def intersection(self, other, sort=False):
start = right[0]

if end < start:
return type(self)(data=[])
return type(self)(data=[], dtype=self.dtype, freq=self.freq)
else:
lslice = slice(*left.slice_locs(start, end))
left_chunk = left.values[lslice]
left_chunk = left._values[lslice]
return self._shallow_copy(left_chunk)

def _can_fast_union(self, other) -> bool:
Expand Down
6 changes: 4 additions & 2 deletions pandas/tests/indexes/datetimes/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ def test_getitem(self):
def test_dti_business_getitem(self):
rng = pd.bdate_range(START, END)
smaller = rng[:5]
exp = DatetimeIndex(rng.view(np.ndarray)[:5])
exp = DatetimeIndex(rng.view(np.ndarray)[:5], freq="B")
tm.assert_index_equal(smaller, exp)
assert smaller.freq == exp.freq

assert smaller.freq == rng.freq

Expand All @@ -102,8 +103,9 @@ def test_dti_business_getitem_matplotlib_hackaround(self):
def test_dti_custom_getitem(self):
rng = pd.bdate_range(START, END, freq="C")
smaller = rng[:5]
exp = DatetimeIndex(rng.view(np.ndarray)[:5])
exp = DatetimeIndex(rng.view(np.ndarray)[:5], freq="C")
tm.assert_index_equal(smaller, exp)
assert smaller.freq == exp.freq
assert smaller.freq == rng.freq

sliced = rng[::5]
Expand Down
26 changes: 24 additions & 2 deletions pandas/tests/indexes/datetimes/test_setops.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,14 +269,34 @@ def test_intersection(self, tz, sort):
assert result.freq is None
assert result.tz == expected.tz

def test_intersection_empty(self):
# parametrize over both anchored and non-anchored freqs, as they
# have different code paths
@pytest.mark.parametrize("freq", ["T", "B"])
def test_intersection_empty(self, tz_aware_fixture, freq):
# empty same freq GH2129
rng = date_range("6/1/2000", "6/15/2000", freq="T")
tz = tz_aware_fixture
rng = date_range("6/1/2000", "6/15/2000", freq=freq, tz=tz)
result = rng[0:0].intersection(rng)
assert len(result) == 0
assert result.freq == rng.freq

result = rng.intersection(rng[0:0])
assert len(result) == 0
assert result.freq == rng.freq

# no overlap GH#33604
result = rng[:3].intersection(rng[-3:])
tm.assert_index_equal(result, rng[:0])
if freq != "T":
# We don't preserve freq on non-anchored offsets
assert result.freq == rng.freq

# swapped left and right
result = rng[-3:].intersection(rng[:3])
tm.assert_index_equal(result, rng[:0])
if freq != "T":
# We don't preserve freq on non-anchored offsets
assert result.freq == rng.freq

def test_intersection_bug_1708(self):
from pandas import DateOffset
Expand Down Expand Up @@ -450,6 +470,7 @@ def test_intersection_bug(self):
b = bdate_range("12/10/2011", "12/20/2011")
result = a.intersection(b)
tm.assert_index_equal(result, b)
assert result.freq == b.freq

def test_month_range_union_tz_pytz(self, sort):
from pytz import timezone
Expand Down Expand Up @@ -527,3 +548,4 @@ def test_intersection_bug(self):
b = bdate_range("12/10/2011", "12/20/2011", freq="C")
result = a.intersection(b)
tm.assert_index_equal(result, b)
assert result.freq == b.freq
5 changes: 3 additions & 2 deletions pandas/tests/indexes/timedeltas/test_setops.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def test_intersection_bug_1708(self):
result = index_1 & index_2
expected = timedelta_range("1 day 01:00:00", periods=3, freq="h")
tm.assert_index_equal(result, expected)
assert result.freq == expected.freq

def test_intersection_equal(self, sort):
# GH 24471 Test intersection outcome given the sort keyword
Expand Down Expand Up @@ -182,7 +183,7 @@ def test_intersection(self, rng, expected, sort):
TimedeltaIndex(["2 hour", "5 hour", "5 hour", "1 hour"], name="other"),
TimedeltaIndex(["1 hour", "2 hour"], name=None),
),
# reveresed index
# reversed index
(
TimedeltaIndex(["1 hour", "2 hour", "4 hour", "3 hour"], name="idx")[
::-1
Expand All @@ -200,7 +201,7 @@ def test_intersection_non_monotonic(self, rng, expected, sort):
tm.assert_index_equal(result, expected)
assert result.name == expected.name

# if reveresed order, frequency is still the same
# if reversed order, frequency is still the same
if all(base == rng[::-1]) and sort is None:
assert isinstance(result.freq, Hour)
else:
Expand Down