From b2dee7a5348bf066e5f6dcbae46223d648000d24 Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 2 Nov 2021 16:28:07 -0700 Subject: [PATCH] BUG: partially-inferring pydatetime objects --- doc/source/whatsnew/v1.4.0.rst | 1 + pandas/core/dtypes/cast.py | 2 +- pandas/tests/series/test_constructors.py | 12 +++++++++++ pandas/tests/tools/test_to_datetime.py | 27 ++++++++++++++++++------ 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 2a718fdcf16e7..46d0ef1bb8ad5 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -475,6 +475,7 @@ Datetimelike - Bug in :meth:`date_range` and :meth:`bdate_range` do not return right bound when ``start`` = ``end`` and set is closed on one side (:issue:`43394`) - Bug in inplace addition and subtraction of :class:`DatetimeIndex` or :class:`TimedeltaIndex` with :class:`DatetimeArray` or :class:`TimedeltaArray` (:issue:`43904`) - Bug in in calling ``np.isnan``, ``np.isfinite``, or ``np.isinf`` on a timezone-aware :class:`DatetimeIndex` incorrectly raising ``TypeError`` (:issue:`43917`) +- Bug in constructing a :class:`Series` from datetime-like strings with mixed timezones incorrectly partially-inferring datetime values (:issue:`40111`) - Timedelta diff --git a/pandas/core/dtypes/cast.py b/pandas/core/dtypes/cast.py index c0ac9098ec7fc..7693f4cd13e9b 100644 --- a/pandas/core/dtypes/cast.py +++ b/pandas/core/dtypes/cast.py @@ -1526,7 +1526,7 @@ def try_datetime(v: np.ndarray) -> ArrayLike: try: # GH#19671 we pass require_iso8601 to be relatively strict # when parsing strings. - dta = sequence_to_datetimes(v, require_iso8601=True, allow_object=True) + dta = sequence_to_datetimes(v, require_iso8601=True, allow_object=False) except (ValueError, TypeError): # e.g. is not convertible to datetime return v.reshape(shape) diff --git a/pandas/tests/series/test_constructors.py b/pandas/tests/series/test_constructors.py index dbf6d5627c00b..2c33284df18c5 100644 --- a/pandas/tests/series/test_constructors.py +++ b/pandas/tests/series/test_constructors.py @@ -1045,6 +1045,18 @@ def test_constructor_with_datetime_tz2(self): expected = Series(DatetimeIndex(["NaT", "NaT"], tz="US/Eastern")) tm.assert_series_equal(s, expected) + def test_constructor_no_partial_datetime_casting(self): + # GH#40111 + vals = [ + "nan", + Timestamp("1990-01-01"), + "2015-03-14T16:15:14.123-08:00", + "2019-03-04T21:56:32.620-07:00", + None, + ] + ser = Series(vals) + assert all(ser[i] is vals[i] for i in range(len(vals))) + @pytest.mark.parametrize("arr_dtype", [np.int64, np.float64]) @pytest.mark.parametrize("dtype", ["M8", "m8"]) @pytest.mark.parametrize("unit", ["ns", "us", "ms", "s", "h", "m", "D"]) diff --git a/pandas/tests/tools/test_to_datetime.py b/pandas/tests/tools/test_to_datetime.py index 3fa6441e47242..1f75bc11005bc 100644 --- a/pandas/tests/tools/test_to_datetime.py +++ b/pandas/tests/tools/test_to_datetime.py @@ -1123,17 +1123,32 @@ def test_iso8601_strings_mixed_offsets_with_naive(self): def test_mixed_offsets_with_native_datetime_raises(self): # GH 25978 - ser = Series( + + vals = [ + "nan", + Timestamp("1990-01-01"), + "2015-03-14T16:15:14.123-08:00", + "2019-03-04T21:56:32.620-07:00", + None, + ] + ser = Series(vals) + assert all(ser[i] is vals[i] for i in range(len(vals))) # GH#40111 + + mixed = to_datetime(ser) + expected = Series( [ - "nan", + "NaT", Timestamp("1990-01-01"), - "2015-03-14T16:15:14.123-08:00", - "2019-03-04T21:56:32.620-07:00", + Timestamp("2015-03-14T16:15:14.123-08:00").to_pydatetime(), + Timestamp("2019-03-04T21:56:32.620-07:00").to_pydatetime(), None, - ] + ], + dtype=object, ) + tm.assert_series_equal(mixed, expected) + with pytest.raises(ValueError, match="Tz-aware datetime.datetime"): - to_datetime(ser) + to_datetime(mixed) def test_non_iso_strings_with_tz_offset(self): result = to_datetime(["March 1, 2018 12:00:00+0400"] * 2)