Skip to content

Commit b1ee2df

Browse files
jbrockmendeljorisvandenbossche
authored andcommitted
REF/TST: Fix remaining DatetimeArray with DateOffset arithmetic ops (#23789)
1 parent 580a094 commit b1ee2df

File tree

9 files changed

+323
-250
lines changed

9 files changed

+323
-250
lines changed

pandas/_libs/tslibs/timestamps.pyx

+4-2
Original file line numberDiff line numberDiff line change
@@ -377,13 +377,15 @@ cdef class _Timestamp(datetime):
377377
neg_other = -other
378378
return self + neg_other
379379

380+
typ = getattr(other, '_typ', None)
381+
380382
# a Timestamp-DatetimeIndex -> yields a negative TimedeltaIndex
381-
elif getattr(other, '_typ', None) == 'datetimeindex':
383+
if typ in ('datetimeindex', 'datetimearray'):
382384
# timezone comparison is performed in DatetimeIndex._sub_datelike
383385
return -other.__sub__(self)
384386

385387
# a Timestamp-TimedeltaIndex -> yields a negative TimedeltaIndex
386-
elif getattr(other, '_typ', None) == 'timedeltaindex':
388+
elif typ in ('timedeltaindex', 'timedeltaarray'):
387389
return (-other).__add__(self)
388390

389391
elif other is NaT:

pandas/core/arrays/timedeltas.py

+36-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import numpy as np
99

10-
from pandas._libs import tslibs
10+
from pandas._libs import algos, tslibs
1111
from pandas._libs.tslibs import NaT, Timedelta, Timestamp, iNaT
1212
from pandas._libs.tslibs.fields import get_timedelta_field
1313
from pandas._libs.tslibs.timedeltas import (
@@ -24,7 +24,7 @@
2424
from pandas.core.dtypes.missing import isna
2525

2626
from pandas.core import ops
27-
from pandas.core.algorithms import checked_add_with_arr
27+
from pandas.core.algorithms import checked_add_with_arr, unique1d
2828
import pandas.core.common as com
2929

3030
from pandas.tseries.frequencies import to_offset
@@ -162,15 +162,29 @@ def _simple_new(cls, values, freq=None, dtype=_TD_DTYPE):
162162
result._freq = freq
163163
return result
164164

165-
def __new__(cls, values, freq=None, dtype=_TD_DTYPE):
165+
def __new__(cls, values, freq=None, dtype=_TD_DTYPE, copy=False):
166166

167167
freq, freq_infer = dtl.maybe_infer_freq(freq)
168168

169-
values = np.array(values, copy=False)
170-
if values.dtype == np.object_:
171-
values = array_to_timedelta64(values)
169+
values, inferred_freq = sequence_to_td64ns(
170+
values, copy=copy, unit=None)
171+
if inferred_freq is not None:
172+
if freq is not None and freq != inferred_freq:
173+
raise ValueError('Inferred frequency {inferred} from passed '
174+
'values does not conform to passed frequency '
175+
'{passed}'
176+
.format(inferred=inferred_freq,
177+
passed=freq.freqstr))
178+
elif freq is None:
179+
freq = inferred_freq
180+
freq_infer = False
172181

173182
result = cls._simple_new(values, freq=freq)
183+
# check that we are matching freqs
184+
if inferred_freq is None and len(result) > 0:
185+
if freq is not None and not freq_infer:
186+
cls._validate_frequency(result, freq)
187+
174188
if freq_infer:
175189
result.freq = to_offset(result.inferred_freq)
176190

@@ -227,6 +241,21 @@ def _validate_fill_value(self, fill_value):
227241
"Got '{got}'.".format(got=fill_value))
228242
return fill_value
229243

244+
# monotonicity/uniqueness properties are called via frequencies.infer_freq,
245+
# see GH#23789
246+
247+
@property
248+
def _is_monotonic_increasing(self):
249+
return algos.is_monotonic(self.asi8, timelike=True)[0]
250+
251+
@property
252+
def _is_monotonic_decreasing(self):
253+
return algos.is_monotonic(self.asi8, timelike=True)[1]
254+
255+
@property
256+
def _is_unique(self):
257+
return len(unique1d(self.asi8)) == len(self)
258+
230259
# ----------------------------------------------------------------
231260
# Arithmetic Methods
232261

@@ -283,7 +312,7 @@ def _add_datetimelike_scalar(self, other):
283312
result = checked_add_with_arr(i8, other.value,
284313
arr_mask=self._isnan)
285314
result = self._maybe_mask_results(result)
286-
return DatetimeArrayMixin(result, tz=other.tz)
315+
return DatetimeArrayMixin(result, tz=other.tz, freq=self.freq)
287316

288317
def _addsub_offset_array(self, other, op):
289318
# Add or subtract Array-like of DateOffset objects

pandas/core/indexes/datetimes.py

+5
Original file line numberDiff line numberDiff line change
@@ -1135,6 +1135,11 @@ def slice_indexer(self, start=None, end=None, step=None, kind=None):
11351135
# --------------------------------------------------------------------
11361136
# Wrapping DatetimeArray
11371137

1138+
# Compat for frequency inference, see GH#23789
1139+
_is_monotonic_increasing = Index.is_monotonic_increasing
1140+
_is_monotonic_decreasing = Index.is_monotonic_decreasing
1141+
_is_unique = Index.is_unique
1142+
11381143
_timezone = cache_readonly(DatetimeArray._timezone.fget)
11391144
is_normalized = cache_readonly(DatetimeArray.is_normalized.fget)
11401145
_resolution = cache_readonly(DatetimeArray._resolution.fget)

pandas/core/indexes/timedeltas.py

+5
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,11 @@ def _format_native_types(self, na_rep=u'NaT', date_format=None, **kwargs):
250250

251251
total_seconds = wrap_array_method(TimedeltaArray.total_seconds, True)
252252

253+
# Compat for frequency inference, see GH#23789
254+
_is_monotonic_increasing = Index.is_monotonic_increasing
255+
_is_monotonic_decreasing = Index.is_monotonic_decreasing
256+
_is_unique = Index.is_unique
257+
253258
# -------------------------------------------------------------------
254259

255260
@Appender(_index_shared_docs['astype'])

0 commit comments

Comments
 (0)