Skip to content

Commit c2d991c

Browse files
committed
BUG: respect freq=None in DTA constructor
1 parent 297c59a commit c2d991c

File tree

6 files changed

+42
-29
lines changed

6 files changed

+42
-29
lines changed

doc/source/whatsnew/v1.5.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,7 @@ Datetimelike
737737
- Bug in :meth:`DatetimeIndex.tz_localize` localizing to UTC failing to make a copy of the underlying data (:issue:`46460`)
738738
- Bug in :meth:`DatetimeIndex.resolution` incorrectly returning "day" instead of "nanosecond" for nanosecond-resolution indexes (:issue:`46903`)
739739
- Bug in :class:`Timestamp` with an integer or float value and ``unit="Y"`` or ``unit="M"`` giving slightly-wrong results (:issue:`47266`)
740+
- Bug in :class:`DatetimeArray` construction when passed another :class:`DatetimeArray` and ``freq=None`` incorrectly inferring the freq from the given array (:issue:`??`)
740741
-
741742

742743
Timedelta

pandas/core/arrays/datetimes.py

+26-19
Original file line numberDiff line numberDiff line change
@@ -256,15 +256,26 @@ class DatetimeArray(dtl.TimelikeOps, dtl.DatelikeOps):
256256
_freq = None
257257

258258
def __init__(
259-
self, values, dtype=DT64NS_DTYPE, freq=None, copy: bool = False
259+
self, values, dtype=DT64NS_DTYPE, freq=lib.no_default, copy: bool = False
260260
) -> None:
261261
values = extract_array(values, extract_numpy=True)
262262
if isinstance(values, IntegerArray):
263263
values = values.to_numpy("int64", na_value=iNaT)
264264

265265
inferred_freq = getattr(values, "_freq", None)
266+
explicit_none = freq is None
267+
freq = freq if freq is not lib.no_default else None
266268

267269
if isinstance(values, type(self)):
270+
if explicit_none:
271+
# don't inherit from values
272+
pass
273+
elif freq is None:
274+
freq = values.freq
275+
elif freq and values.freq:
276+
freq = to_offset(freq)
277+
freq, _ = dtl.validate_inferred_freq(freq, values.freq, False)
278+
268279
# validation
269280
dtz = getattr(dtype, "tz", None)
270281
if dtz and values.tz is None:
@@ -279,14 +290,13 @@ def __init__(
279290
elif values.tz:
280291
dtype = values.dtype
281292

282-
if freq is None:
283-
freq = values.freq
284293
values = values._ndarray
285294

286295
if not isinstance(values, np.ndarray):
287296
raise ValueError(
288-
f"Unexpected type '{type(values).__name__}'. 'values' must be "
289-
"a DatetimeArray, ndarray, or Series or Index containing one of those."
297+
f"Unexpected type '{type(values).__name__}'. 'values' must be a "
298+
f"{type(self).__name__}, ndarray, or Series or Index "
299+
"containing one of those."
290300
)
291301
if values.ndim not in [1, 2]:
292302
raise ValueError("Only 1-dimensional input arrays are supported.")
@@ -297,31 +307,19 @@ def __init__(
297307
# nanosecond UTC (or tz-naive) unix timestamps
298308
values = values.view(DT64NS_DTYPE)
299309

300-
if values.dtype != DT64NS_DTYPE:
301-
raise ValueError(
302-
"The dtype of 'values' is incorrect. Must be 'datetime64[ns]'. "
303-
f"Got {values.dtype} instead."
304-
)
305-
310+
_validate_dt64_dtype(values.dtype)
306311
dtype = _validate_dt64_dtype(dtype)
307312

308313
if freq == "infer":
309314
raise ValueError(
310-
"Frequency inference not allowed in DatetimeArray.__init__. "
315+
f"Frequency inference not allowed in {type(self).__name__}.__init__. "
311316
"Use 'pd.array()' instead."
312317
)
313318

314319
if copy:
315320
values = values.copy()
316321
if freq:
317322
freq = to_offset(freq)
318-
if getattr(dtype, "tz", None):
319-
# https://github.com/pandas-dev/pandas/issues/18595
320-
# Ensure that we have a standard timezone for pytz objects.
321-
# Without this, things like adding an array of timedeltas and
322-
# a tz-aware Timestamp (with a tz specific to its datetime) will
323-
# be incorrect(ish?) for the array as a whole
324-
dtype = DatetimeTZDtype(tz=timezones.tz_standardize(dtype.tz))
325323

326324
NDArrayBacked.__init__(self, values=values, dtype=dtype)
327325
self._freq = freq
@@ -2394,6 +2392,15 @@ def _validate_dt64_dtype(dtype):
23942392
f"Unexpected value for 'dtype': '{dtype}'. "
23952393
"Must be 'datetime64[ns]' or DatetimeTZDtype'."
23962394
)
2395+
2396+
if getattr(dtype, "tz", None):
2397+
# https://github.com/pandas-dev/pandas/issues/18595
2398+
# Ensure that we have a standard timezone for pytz objects.
2399+
# Without this, things like adding an array of timedeltas and
2400+
# a tz-aware Timestamp (with a tz specific to its datetime) will
2401+
# be incorrect(ish?) for the array as a whole
2402+
dtype = DatetimeTZDtype(tz=timezones.tz_standardize(dtype.tz))
2403+
23972404
return dtype
23982405

23992406

pandas/core/arrays/timedeltas.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -186,21 +186,22 @@ def __init__(
186186

187187
if isinstance(values, type(self)):
188188
if explicit_none:
189-
# dont inherit from values
189+
# don't inherit from values
190190
pass
191191
elif freq is None:
192192
freq = values.freq
193193
elif freq and values.freq:
194194
freq = to_offset(freq)
195195
freq, _ = dtl.validate_inferred_freq(freq, values.freq, False)
196+
196197
values = values._ndarray
197198

198199
if not isinstance(values, np.ndarray):
199-
msg = (
200+
raise ValueError(
200201
f"Unexpected type '{type(values).__name__}'. 'values' must be a "
201-
"TimedeltaArray, ndarray, or Series or Index containing one of those."
202+
f"{type(self).__name__}, ndarray, or Series or Index "
203+
"containing one of those."
202204
)
203-
raise ValueError(msg)
204205
if values.ndim not in [1, 2]:
205206
raise ValueError("Only 1-dimensional input arrays are supported.")
206207

@@ -214,11 +215,10 @@ def __init__(
214215
dtype = _validate_td64_dtype(dtype)
215216

216217
if freq == "infer":
217-
msg = (
218-
"Frequency inference not allowed in TimedeltaArray.__init__. "
218+
raise ValueError(
219+
f"Frequency inference not allowed in {type(self).__name__}.__init__. "
219220
"Use 'pd.array()' instead."
220221
)
221-
raise ValueError(msg)
222222

223223
if copy:
224224
values = values.copy()

pandas/tests/arrays/datetimes/test_constructors.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,8 @@ def test_non_array_raises(self):
8787
def test_bool_dtype_raises(self):
8888
arr = np.array([1, 2, 3], dtype="bool")
8989

90-
with pytest.raises(
91-
ValueError, match="The dtype of 'values' is incorrect.*bool"
92-
):
90+
msg = "Unexpected value for 'dtype': 'bool'. Must be"
91+
with pytest.raises(ValueError, match=msg):
9392
DatetimeArray(arr)
9493

9594
msg = r"dtype bool cannot be converted to datetime64\[ns\]"

pandas/tests/indexes/datetimes/test_constructors.py

+3
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,9 @@ def test_explicit_none_freq(self):
925925
result = DatetimeIndex(rng._data, freq=None)
926926
assert result.freq is None
927927

928+
dta = DatetimeArray(rng, freq=None)
929+
assert dta.freq is None
930+
928931
def test_dti_constructor_years_only(self, tz_naive_fixture):
929932
tz = tz_naive_fixture
930933
# GH 6961

pandas/tests/indexes/timedeltas/test_constructors.py

+3
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ def test_explicit_none_freq(self):
263263
result = TimedeltaIndex(tdi._data, freq=None)
264264
assert result.freq is None
265265

266+
tda = TimedeltaArray(tdi, freq=None)
267+
assert tda.freq is None
268+
266269
def test_from_categorical(self):
267270
tdi = timedelta_range(1, periods=5)
268271

0 commit comments

Comments
 (0)