Skip to content

Commit 20f51b7

Browse files
jbrockmendelAlexKirko
authored andcommitted
INT: Implement _set_freq for TDI/DTI (pandas-dev#30495)
1 parent 6b9dd3c commit 20f51b7

File tree

4 files changed

+48
-16
lines changed

4 files changed

+48
-16
lines changed

pandas/core/indexes/datetimelike.py

+34-7
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from pandas.core.indexes.base import Index, _index_shared_docs
3636
from pandas.core.tools.timedeltas import to_timedelta
3737

38-
from pandas.tseries.frequencies import to_offset
38+
from pandas.tseries.frequencies import DateOffset, to_offset
3939

4040
_index_doc_kwargs = dict(ibase._index_doc_kwargs)
4141

@@ -71,6 +71,36 @@ def method(self, other):
7171
return method
7272

7373

74+
class DatetimeTimedeltaMixin:
75+
"""
76+
Mixin class for methods shared by DatetimeIndex and TimedeltaIndex,
77+
but not PeriodIndex
78+
"""
79+
80+
def _set_freq(self, freq):
81+
"""
82+
Set the _freq attribute on our underlying DatetimeArray.
83+
84+
Parameters
85+
----------
86+
freq : DateOffset, None, or "infer"
87+
"""
88+
# GH#29843
89+
if freq is None:
90+
# Always valid
91+
pass
92+
elif len(self) == 0 and isinstance(freq, DateOffset):
93+
# Always valid. In the TimedeltaIndex case, we assume this
94+
# is a Tick offset.
95+
pass
96+
else:
97+
# As an internal method, we can ensure this assertion always holds
98+
assert freq == "infer"
99+
freq = to_offset(self.inferred_freq)
100+
101+
self._data._freq = freq
102+
103+
74104
class DatetimeIndexOpsMixin(ExtensionOpsMixin):
75105
"""
76106
Common ops mixin to support a unified interface datetimelike Index.
@@ -592,8 +622,7 @@ def intersection(self, other, sort=False):
592622
result = Index.intersection(self, other, sort=sort)
593623
if isinstance(result, type(self)):
594624
if result.freq is None:
595-
# TODO: find a less code-smelly way to set this
596-
result._data._freq = to_offset(result.inferred_freq)
625+
result._set_freq("infer")
597626
return result
598627

599628
elif (
@@ -608,17 +637,15 @@ def intersection(self, other, sort=False):
608637
# Invalidate the freq of `result`, which may not be correct at
609638
# this point, depending on the values.
610639

611-
# TODO: find a less code-smelly way to set this
612-
result._data._freq = None
640+
result._set_freq(None)
613641
if hasattr(self, "tz"):
614642
result = self._shallow_copy(
615643
result._values, name=result.name, tz=result.tz, freq=None
616644
)
617645
else:
618646
result = self._shallow_copy(result._values, name=result.name, freq=None)
619647
if result.freq is None:
620-
# TODO: find a less code-smelly way to set this
621-
result._data._freq = to_offset(result.inferred_freq)
648+
result._set_freq("infer")
622649
return result
623650

624651
# to make our life easier, "sort" the two ranges

pandas/core/indexes/datetimes.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from pandas.core.indexes.datetimelike import (
3535
DatetimeIndexOpsMixin,
3636
DatetimelikeDelegateMixin,
37+
DatetimeTimedeltaMixin,
3738
ea_passthrough,
3839
)
3940
from pandas.core.indexes.numeric import Int64Index
@@ -93,7 +94,9 @@ class DatetimeDelegateMixin(DatetimelikeDelegateMixin):
9394
typ="method",
9495
overwrite=False,
9596
)
96-
class DatetimeIndex(DatetimeIndexOpsMixin, Int64Index, DatetimeDelegateMixin):
97+
class DatetimeIndex(
98+
DatetimeTimedeltaMixin, DatetimeIndexOpsMixin, Int64Index, DatetimeDelegateMixin
99+
):
97100
"""
98101
Immutable ndarray of datetime64 data, represented internally as int64, and
99102
which can be boxed to Timestamp objects that are subclasses of datetime and
@@ -412,7 +415,7 @@ def _convert_for_op(self, value):
412415
@Appender(Index.difference.__doc__)
413416
def difference(self, other, sort=None):
414417
new_idx = super().difference(other, sort=sort)
415-
new_idx._data._freq = None
418+
new_idx._set_freq(None)
416419
return new_idx
417420

418421
# --------------------------------------------------------------------

pandas/core/indexes/timedeltas.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from pandas.core.indexes.datetimelike import (
3030
DatetimeIndexOpsMixin,
3131
DatetimelikeDelegateMixin,
32+
DatetimeTimedeltaMixin,
3233
ea_passthrough,
3334
)
3435
from pandas.core.indexes.numeric import Int64Index
@@ -64,7 +65,11 @@ class TimedeltaDelegateMixin(DatetimelikeDelegateMixin):
6465
overwrite=True,
6566
)
6667
class TimedeltaIndex(
67-
DatetimeIndexOpsMixin, dtl.TimelikeOps, Int64Index, TimedeltaDelegateMixin
68+
DatetimeTimedeltaMixin,
69+
DatetimeIndexOpsMixin,
70+
dtl.TimelikeOps,
71+
Int64Index,
72+
TimedeltaDelegateMixin,
6873
):
6974
"""
7075
Immutable ndarray of timedelta64 data, represented internally as int64, and
@@ -296,8 +301,7 @@ def _union(self, other, sort):
296301
result = Index._union(this, other, sort=sort)
297302
if isinstance(result, TimedeltaIndex):
298303
if result.freq is None:
299-
# TODO: find a less code-smelly way to set this
300-
result._data._freq = to_offset(result.inferred_freq)
304+
result._set_freq("infer")
301305
return result
302306

303307
def join(self, other, how="left", level=None, return_indexers=False, sort=False):
@@ -350,8 +354,7 @@ def intersection(self, other, sort=False):
350354
@Appender(Index.difference.__doc__)
351355
def difference(self, other, sort=None):
352356
new_idx = super().difference(other, sort=sort)
353-
# TODO: find a less code-smelly way to set this
354-
new_idx._data._freq = None
357+
new_idx._set_freq(None)
355358
return new_idx
356359

357360
def _wrap_joined_index(self, joined, other):

pandas/core/resample.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -1025,8 +1025,7 @@ def _downsample(self, how, **kwargs):
10251025
if not len(ax):
10261026
# reset to the new freq
10271027
obj = obj.copy()
1028-
# TODO: find a less code-smelly way to set this
1029-
obj.index._data._freq = self.freq
1028+
obj.index._set_freq(self.freq)
10301029
return obj
10311030

10321031
# do we have a regular frequency

0 commit comments

Comments
 (0)