From a8bbe75dc2d6e05900648490a96ec8bb7b9e8e0e Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Thu, 18 Jun 2020 08:47:44 +0200 Subject: [PATCH] BUG: fix construction from read-only non-ns datetime64 numpy array (#34844) --- doc/source/whatsnew/v1.1.0.rst | 3 +++ pandas/_libs/tslibs/conversion.pyx | 3 ++- pandas/tests/base/test_constructors.py | 24 ++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 10522ff797c59..6a6c7ebd49db1 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -843,6 +843,9 @@ Datetimelike - Bug in :meth:`DatetimeIndex.intersection` and :meth:`TimedeltaIndex.intersection` with results not having the correct ``name`` attribute (:issue:`33904`) - Bug in :meth:`DatetimeArray.__setitem__`, :meth:`TimedeltaArray.__setitem__`, :meth:`PeriodArray.__setitem__` incorrectly allowing values with ``int64`` dtype to be silently cast (:issue:`33717`) - Bug in subtracting :class:`TimedeltaIndex` from :class:`Period` incorrectly raising ``TypeError`` in some cases where it should succeed and ``IncompatibleFrequency`` in some cases where it should raise ``TypeError`` (:issue:`33883`) +- Bug in constructing a Series or Index from a read-only NumPy array with non-ns + resolution which converted to object dtype instead of coercing to ``datetime64[ns]`` + dtype when within the timestamp bounds (:issue:`34843`). - The ``freq`` keyword in :class:`Period`, :func:`date_range`, :func:`period_range`, :func:`pd.tseries.frequencies.to_offset` no longer allows tuples, pass as string instead (:issue:`34703`) Timedelta diff --git a/pandas/_libs/tslibs/conversion.pyx b/pandas/_libs/tslibs/conversion.pyx index 40b2d44235d8b..0811ba22977fd 100644 --- a/pandas/_libs/tslibs/conversion.pyx +++ b/pandas/_libs/tslibs/conversion.pyx @@ -167,7 +167,8 @@ def ensure_datetime64ns(arr: ndarray, copy: bool=True): """ cdef: Py_ssize_t i, n = arr.size - int64_t[:] ivalues, iresult + const int64_t[:] ivalues + int64_t[:] iresult NPY_DATETIMEUNIT unit npy_datetimestruct dts diff --git a/pandas/tests/base/test_constructors.py b/pandas/tests/base/test_constructors.py index e27b5c307cd99..697364fc87175 100644 --- a/pandas/tests/base/test_constructors.py +++ b/pandas/tests/base/test_constructors.py @@ -13,6 +13,19 @@ from pandas.core.base import NoNewAttributesMixin, PandasObject +@pytest.fixture( + params=[ + Series, + lambda x, **kwargs: DataFrame({"a": x}, **kwargs)["a"], + lambda x, **kwargs: DataFrame(x, **kwargs)[0], + Index, + ], + ids=["Series", "DataFrame-dict", "DataFrame-array", "Index"], +) +def constructor(request): + return request.param + + class TestPandasDelegate: class Delegator: _properties = ["foo"] @@ -145,3 +158,14 @@ def test_constructor_datetime_outofbound(self, a, klass): msg = "Out of bounds" with pytest.raises(pd.errors.OutOfBoundsDatetime, match=msg): klass(a, dtype="datetime64[ns]") + + def test_constructor_datetime_nonns(self, constructor): + arr = np.array(["2020-01-01T00:00:00.000000"], dtype="datetime64[us]") + expected = constructor(pd.to_datetime(["2020-01-01"])) + result = constructor(arr) + tm.assert_equal(result, expected) + + # https://github.com/pandas-dev/pandas/issues/34843 + arr.flags.writeable = False + result = constructor(arr) + tm.assert_equal(result, expected)