From bd0aa06271e02721ba3f2a23fcb310911f7734e4 Mon Sep 17 00:00:00 2001 From: Luke Manley Date: Wed, 12 Jul 2023 20:28:28 -0400 Subject: [PATCH 1/3] BUG: Timestamp(pd.NA) raising TypeError --- doc/source/whatsnew/v2.1.0.rst | 1 + pandas/_libs/tslibs/timestamps.pyx | 4 ++++ pandas/tests/scalar/timestamp/test_constructors.py | 9 +++++++++ 3 files changed, 14 insertions(+) diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index 7450fc6fdc1da..d1f5c61ce4627 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -393,6 +393,7 @@ Datetimelike - Bug in :meth:`Timestamp.round` with values close to the implementation bounds returning incorrect results instead of raising ``OutOfBoundsDatetime`` (:issue:`51494`) - Bug in :meth:`arrays.DatetimeArray.map` and :meth:`DatetimeIndex.map`, where the supplied callable operated array-wise instead of element-wise (:issue:`51977`) - Bug in constructing a :class:`Series` or :class:`DataFrame` from a datetime or timedelta scalar always inferring nanosecond resolution instead of inferring from the input (:issue:`52212`) +- Bug in constructing a :class:`Timestamp` with ``ts_input=pd.NA`` raising ``TypeError`` (:issue:`45481`) - Bug in parsing datetime strings with weekday but no day e.g. "2023 Sept Thu" incorrectly raising ``AttributeError`` instead of ``ValueError`` (:issue:`52659`) Timedelta diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 844fc8f0ed187..80b7c2d2f5b5a 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -47,6 +47,7 @@ import_datetime() import datetime as dt +from pandas._libs.missing cimport checknull_with_nat_and_na from pandas._libs.tslibs cimport ccalendar from pandas._libs.tslibs.base cimport ABCTimestamp @@ -1881,6 +1882,9 @@ class Timestamp(_Timestamp): hour or 0, minute or 0, second or 0, fold=fold or 0) unit = None + elif checknull_with_nat_and_na(ts_input): + return NaT + if getattr(ts_input, "tzinfo", None) is not None and tz is not None: raise ValueError("Cannot pass a datetime or Timestamp with tzinfo with " "the tz parameter. Use tz_convert instead.") diff --git a/pandas/tests/scalar/timestamp/test_constructors.py b/pandas/tests/scalar/timestamp/test_constructors.py index 5fca577ff28d1..6128cf388e5f7 100644 --- a/pandas/tests/scalar/timestamp/test_constructors.py +++ b/pandas/tests/scalar/timestamp/test_constructors.py @@ -18,6 +18,8 @@ from pandas.errors import OutOfBoundsDatetime from pandas import ( + NA, + NaT, Period, Timedelta, Timestamp, @@ -893,3 +895,10 @@ def test_timestamp_constructor_adjust_value_for_fold(tz, ts_input, fold, value_o result = ts._value expected = value_out assert result == expected + + +@pytest.mark.parametrize("na_value", [None, np.nan, NA]) +def test_timestamp_constructor_na_value(na_value): + result = Timestamp(na_value) + expected = NaT + assert result is expected From 90647623b498901e7eaca97a385830474e92da44 Mon Sep 17 00:00:00 2001 From: Marco Edward Gorelli Date: Thu, 13 Jul 2023 12:19:13 +0100 Subject: [PATCH 2/3] Update pandas/tests/scalar/timestamp/test_constructors.py --- pandas/tests/scalar/timestamp/test_constructors.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/tests/scalar/timestamp/test_constructors.py b/pandas/tests/scalar/timestamp/test_constructors.py index 6128cf388e5f7..72f21e80ceca1 100644 --- a/pandas/tests/scalar/timestamp/test_constructors.py +++ b/pandas/tests/scalar/timestamp/test_constructors.py @@ -899,6 +899,7 @@ def test_timestamp_constructor_adjust_value_for_fold(tz, ts_input, fold, value_o @pytest.mark.parametrize("na_value", [None, np.nan, NA]) def test_timestamp_constructor_na_value(na_value): + # GH45481 result = Timestamp(na_value) expected = NaT assert result is expected From 718d810b349ef3bdcca732fab8499621d6479bdb Mon Sep 17 00:00:00 2001 From: Luke Manley Date: Thu, 13 Jul 2023 18:45:04 -0400 Subject: [PATCH 3/3] move check to conversion.pyx --- pandas/_libs/tslibs/conversion.pyx | 4 ++-- pandas/_libs/tslibs/timestamps.pyx | 4 ---- pandas/tests/scalar/timestamp/test_constructors.py | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/pandas/_libs/tslibs/conversion.pyx b/pandas/_libs/tslibs/conversion.pyx index 57b7754b08289..45c4d7809fe7a 100644 --- a/pandas/_libs/tslibs/conversion.pyx +++ b/pandas/_libs/tslibs/conversion.pyx @@ -25,6 +25,7 @@ from cpython.datetime cimport ( import_datetime() +from pandas._libs.missing cimport checknull_with_nat_and_na from pandas._libs.tslibs.base cimport ABCTimestamp from pandas._libs.tslibs.dtypes cimport ( abbrev_to_npy_unit, @@ -57,7 +58,6 @@ from pandas._libs.tslibs.np_datetime import OutOfBoundsDatetime from pandas._libs.tslibs.nattype cimport ( NPY_NAT, - c_NaT as NaT, c_nat_strings as nat_strings, ) from pandas._libs.tslibs.parsing cimport parse_datetime_string @@ -268,7 +268,7 @@ cdef _TSObject convert_to_tsobject(object ts, tzinfo tz, str unit, if isinstance(ts, str): return convert_str_to_tsobject(ts, tz, unit, dayfirst, yearfirst) - if ts is None or ts is NaT: + if checknull_with_nat_and_na(ts): obj.value = NPY_NAT elif is_datetime64_object(ts): reso = get_supported_reso(get_datetime64_unit(ts)) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 80b7c2d2f5b5a..844fc8f0ed187 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -47,7 +47,6 @@ import_datetime() import datetime as dt -from pandas._libs.missing cimport checknull_with_nat_and_na from pandas._libs.tslibs cimport ccalendar from pandas._libs.tslibs.base cimport ABCTimestamp @@ -1882,9 +1881,6 @@ class Timestamp(_Timestamp): hour or 0, minute or 0, second or 0, fold=fold or 0) unit = None - elif checknull_with_nat_and_na(ts_input): - return NaT - if getattr(ts_input, "tzinfo", None) is not None and tz is not None: raise ValueError("Cannot pass a datetime or Timestamp with tzinfo with " "the tz parameter. Use tz_convert instead.") diff --git a/pandas/tests/scalar/timestamp/test_constructors.py b/pandas/tests/scalar/timestamp/test_constructors.py index 0932d0f67bca8..1e1604288a7aa 100644 --- a/pandas/tests/scalar/timestamp/test_constructors.py +++ b/pandas/tests/scalar/timestamp/test_constructors.py @@ -902,7 +902,7 @@ def test_timestamp_constructor_adjust_value_for_fold(tz, ts_input, fold, value_o assert result == expected -@pytest.mark.parametrize("na_value", [None, np.nan, NA]) +@pytest.mark.parametrize("na_value", [None, np.nan, np.datetime64("NaT"), NaT, NA]) def test_timestamp_constructor_na_value(na_value): result = Timestamp(na_value) expected = NaT