Skip to content

Commit 6ba0d7f

Browse files
authored
BUG: IntervalIndex.from_arrays with mismatched datetimelike resos (#55714)
* BUG: IntervalIndex.from_arrays with mismatched datetimelike resos * GH ref
1 parent 0a7477b commit 6ba0d7f

File tree

3 files changed

+29
-0
lines changed

3 files changed

+29
-0
lines changed

doc/source/whatsnew/v2.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ Strings
360360
Interval
361361
^^^^^^^^
362362
- Bug in :class:`Interval` ``__repr__`` not displaying UTC offsets for :class:`Timestamp` bounds. Additionally the hour, minute and second components will now be shown. (:issue:`55015`)
363+
- Bug in :meth:`IntervalIndex.from_arrays` when passed ``datetime64`` or ``timedelta64`` arrays with mismatched resolutions constructing an invalid ``IntervalArray`` object (:issue:`55714`)
363364
- Bug in :meth:`IntervalIndex.get_indexer` with datetime or timedelta intervals incorrectly matching on integer targets (:issue:`47772`)
364365
- Bug in :meth:`IntervalIndex.get_indexer` with timezone-aware datetime intervals incorrectly matching on a sequence of timezone-naive targets (:issue:`47772`)
365366
- Bug in setting values on a :class:`Series` with an :class:`IntervalIndex` using a slice incorrectly raising (:issue:`54722`)

pandas/core/arrays/interval.py

+5
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,11 @@ def _ensure_simple_new_inputs(
357357
f"'{left.tz}' and '{right.tz}'"
358358
)
359359
raise ValueError(msg)
360+
elif needs_i8_conversion(left.dtype) and left.unit != right.unit:
361+
# e.g. m8[s] vs m8[ms], try to cast to a common dtype GH#55714
362+
left_arr, right_arr = left._data._ensure_matching_resos(right._data)
363+
left = ensure_index(left_arr)
364+
right = ensure_index(right_arr)
360365

361366
# For dt64/td64 we want DatetimeArray/TimedeltaArray instead of ndarray
362367
left = ensure_wrapped_if_datetimelike(left)

pandas/tests/indexes/interval/test_constructors.py

+23
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,29 @@ def test_mixed_float_int(self, left_subtype, right_subtype):
256256
tm.assert_index_equal(result.right, expected_right)
257257
assert result.dtype.subtype == expected_subtype
258258

259+
@pytest.mark.parametrize("interval_cls", [IntervalArray, IntervalIndex])
260+
def test_from_arrays_mismatched_datetimelike_resos(self, interval_cls):
261+
# GH#55714
262+
left = date_range("2016-01-01", periods=3, unit="s")
263+
right = date_range("2017-01-01", periods=3, unit="ms")
264+
result = interval_cls.from_arrays(left, right)
265+
expected = interval_cls.from_arrays(left.as_unit("ms"), right)
266+
tm.assert_equal(result, expected)
267+
268+
# td64
269+
left2 = left - left[0]
270+
right2 = right - left[0]
271+
result2 = interval_cls.from_arrays(left2, right2)
272+
expected2 = interval_cls.from_arrays(left2.as_unit("ms"), right2)
273+
tm.assert_equal(result2, expected2)
274+
275+
# dt64tz
276+
left3 = left.tz_localize("UTC")
277+
right3 = right.tz_localize("UTC")
278+
result3 = interval_cls.from_arrays(left3, right3)
279+
expected3 = interval_cls.from_arrays(left3.as_unit("ms"), right3)
280+
tm.assert_equal(result3, expected3)
281+
259282

260283
class TestFromBreaks(ConstructorTests):
261284
"""Tests specific to IntervalIndex.from_breaks"""

0 commit comments

Comments
 (0)