From 1d74b24e599ad945d253f2c40011534464eb40ad Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 26 Oct 2023 15:45:09 -0700 Subject: [PATCH 1/2] BUG: IntervalIndex.from_arrays with mismatched datetimelike resos --- doc/source/whatsnew/v2.2.0.rst | 1 + pandas/core/arrays/interval.py | 5 +++++ .../indexes/interval/test_constructors.py | 22 +++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index 795d277268e44..ff5747679100d 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -361,6 +361,7 @@ Interval - Bug in :meth:`IntervalIndex.get_indexer` with datetime or timedelta intervals incorrectly matching on integer targets (:issue:`47772`) - Bug in :meth:`IntervalIndex.get_indexer` with timezone-aware datetime intervals incorrectly matching on a sequence of timezone-naive targets (:issue:`47772`) - Bug in setting values on a :class:`Series` with an :class:`IntervalIndex` using a slice incorrectly raising (:issue:`54722`) +- Bug in :meth:`IntervalIndex.from_arrays` when passed ``datetime64`` or ``timedelta64`` arrays with mismatched resolutions constructing an invalid ``IntervalArray`` object (:issue:`??`) - Indexing diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 4bc30d6dbd029..7240558d4472d 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -357,6 +357,11 @@ def _ensure_simple_new_inputs( f"'{left.tz}' and '{right.tz}'" ) raise ValueError(msg) + elif needs_i8_conversion(left.dtype) and left.unit != right.unit: + # e.g. m8[s] vs m8[ms], try to cast to a common dtype + left_arr, right_arr = left._data._ensure_matching_resos(right._data) + left = ensure_index(left_arr) + right = ensure_index(right_arr) # For dt64/td64 we want DatetimeArray/TimedeltaArray instead of ndarray left = ensure_wrapped_if_datetimelike(left) diff --git a/pandas/tests/indexes/interval/test_constructors.py b/pandas/tests/indexes/interval/test_constructors.py index 9524288b33eef..bd39fafb994fd 100644 --- a/pandas/tests/indexes/interval/test_constructors.py +++ b/pandas/tests/indexes/interval/test_constructors.py @@ -256,6 +256,28 @@ def test_mixed_float_int(self, left_subtype, right_subtype): tm.assert_index_equal(result.right, expected_right) assert result.dtype.subtype == expected_subtype + @pytest.mark.parametrize("interval_cls", [IntervalArray, IntervalIndex]) + def test_from_arrays_mismatched_datetimelike_resos(self, interval_cls): + left = date_range("2016-01-01", periods=3, unit="s") + right = date_range("2017-01-01", periods=3, unit="ms") + result = interval_cls.from_arrays(left, right) + expected = interval_cls.from_arrays(left.as_unit("ms"), right) + tm.assert_equal(result, expected) + + # td64 + left2 = left - left[0] + right2 = right - left[0] + result2 = interval_cls.from_arrays(left2, right2) + expected2 = interval_cls.from_arrays(left2.as_unit("ms"), right2) + tm.assert_equal(result2, expected2) + + # dt64tz + left3 = left.tz_localize("UTC") + right3 = right.tz_localize("UTC") + result3 = interval_cls.from_arrays(left3, right3) + expected3 = interval_cls.from_arrays(left3.as_unit("ms"), right3) + tm.assert_equal(result3, expected3) + class TestFromBreaks(ConstructorTests): """Tests specific to IntervalIndex.from_breaks""" From ce207d3b7336c33164b53071ef3eee3e24e1b118 Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 26 Oct 2023 15:46:42 -0700 Subject: [PATCH 2/2] GH ref --- doc/source/whatsnew/v2.2.0.rst | 2 +- pandas/core/arrays/interval.py | 2 +- pandas/tests/indexes/interval/test_constructors.py | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index ff5747679100d..d36f990240c5b 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -358,10 +358,10 @@ Strings Interval ^^^^^^^^ - 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`) +- Bug in :meth:`IntervalIndex.from_arrays` when passed ``datetime64`` or ``timedelta64`` arrays with mismatched resolutions constructing an invalid ``IntervalArray`` object (:issue:`55714`) - Bug in :meth:`IntervalIndex.get_indexer` with datetime or timedelta intervals incorrectly matching on integer targets (:issue:`47772`) - Bug in :meth:`IntervalIndex.get_indexer` with timezone-aware datetime intervals incorrectly matching on a sequence of timezone-naive targets (:issue:`47772`) - Bug in setting values on a :class:`Series` with an :class:`IntervalIndex` using a slice incorrectly raising (:issue:`54722`) -- Bug in :meth:`IntervalIndex.from_arrays` when passed ``datetime64`` or ``timedelta64`` arrays with mismatched resolutions constructing an invalid ``IntervalArray`` object (:issue:`??`) - Indexing diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 7240558d4472d..28ee6b2476b0d 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -358,7 +358,7 @@ def _ensure_simple_new_inputs( ) raise ValueError(msg) elif needs_i8_conversion(left.dtype) and left.unit != right.unit: - # e.g. m8[s] vs m8[ms], try to cast to a common dtype + # e.g. m8[s] vs m8[ms], try to cast to a common dtype GH#55714 left_arr, right_arr = left._data._ensure_matching_resos(right._data) left = ensure_index(left_arr) right = ensure_index(right_arr) diff --git a/pandas/tests/indexes/interval/test_constructors.py b/pandas/tests/indexes/interval/test_constructors.py index bd39fafb994fd..1efe5ff980f6c 100644 --- a/pandas/tests/indexes/interval/test_constructors.py +++ b/pandas/tests/indexes/interval/test_constructors.py @@ -258,6 +258,7 @@ def test_mixed_float_int(self, left_subtype, right_subtype): @pytest.mark.parametrize("interval_cls", [IntervalArray, IntervalIndex]) def test_from_arrays_mismatched_datetimelike_resos(self, interval_cls): + # GH#55714 left = date_range("2016-01-01", periods=3, unit="s") right = date_range("2017-01-01", periods=3, unit="ms") result = interval_cls.from_arrays(left, right)