From 5d7172adeaa8eca1fb2e98018cb1676f2959c182 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Wed, 21 Sep 2022 12:25:20 -0700 Subject: [PATCH 1/2] DEPR: Timestamp(nanoseconds>999) --- doc/source/whatsnew/v1.6.0.rst | 2 +- pandas/_libs/tslibs/timestamps.pyx | 13 ++++++++++++- pandas/tests/scalar/timestamp/test_constructors.py | 7 +++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v1.6.0.rst b/doc/source/whatsnew/v1.6.0.rst index 050dfacc13df0..2154ca19042af 100644 --- a/doc/source/whatsnew/v1.6.0.rst +++ b/doc/source/whatsnew/v1.6.0.rst @@ -124,7 +124,7 @@ Other API changes Deprecations ~~~~~~~~~~~~ - -- +- Deprecated passing ``nanoseconds`` greater than 999 or less than 0 in :class:`Timestamp` (:issue:`48538`, :issue:`48255`) .. --------------------------------------------------------------------------- .. _whatsnew_160.performance: diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 07c6e32028942..dd597f661a2cc 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -1692,7 +1692,18 @@ class Timestamp(_Timestamp): ) # Once this deprecation is enforced, we can do # return Timestamp(ts_input).tz_localize(tzobj) - ts = convert_to_tsobject(ts_input, tzobj, unit, 0, 0, nanosecond or 0) + if nanosecond is None: + nanosecond = 0 + elif not (999 >= nanosecond >= 0): + warnings.warn( + "In a future version, nanosecond must be between 0 and 999 inclusive " + "and will raise a ValueError otherwise. For nanoseconds > 999, " + "please distribute excess nanoseconds to microseconds and " + "other components as needed.", + FutureWarning, + stacklevel=find_stack_level(inspect.currentframe()), + ) + ts = convert_to_tsobject(ts_input, tzobj, unit, 0, 0, nanosecond) if ts.value == NPY_NAT: return NaT diff --git a/pandas/tests/scalar/timestamp/test_constructors.py b/pandas/tests/scalar/timestamp/test_constructors.py index 7b3647dc6cbef..b8166438b78c1 100644 --- a/pandas/tests/scalar/timestamp/test_constructors.py +++ b/pandas/tests/scalar/timestamp/test_constructors.py @@ -677,3 +677,10 @@ def test_constructor_missing_keyword(kwargs): with pytest.raises(TypeError, match=msg): Timestamp(**kwargs) + + +@pytest.mark.parametrize("nano", [-1, 1000]) +def test_timestamp_nano_range_deprecated(nano): + # GH 48255 + with tm.assert_produces_warning(FutureWarning): + Timestamp(year=2022, month=1, day=1, nanosecond=nano) From e783410c1559fe62a9e02c74c186b741648d8ca6 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Thu, 22 Sep 2022 13:09:50 -0700 Subject: [PATCH 2/2] Change to ValueError --- doc/source/whatsnew/v1.6.0.rst | 4 ++-- pandas/_libs/tslibs/timestamps.pyx | 11 +++-------- pandas/tests/scalar/timestamp/test_constructors.py | 4 ++-- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/doc/source/whatsnew/v1.6.0.rst b/doc/source/whatsnew/v1.6.0.rst index 2154ca19042af..5b085da0d6f72 100644 --- a/doc/source/whatsnew/v1.6.0.rst +++ b/doc/source/whatsnew/v1.6.0.rst @@ -116,7 +116,7 @@ See :ref:`install.dependencies` and :ref:`install.optional_dependencies` for mor Other API changes ^^^^^^^^^^^^^^^^^ - -- +- Passing ``nanoseconds`` greater than 999 or less than 0 in :class:`Timestamp` now raises a ``ValueError`` (:issue:`48538`, :issue:`48255`) .. --------------------------------------------------------------------------- .. _whatsnew_160.deprecations: @@ -124,7 +124,7 @@ Other API changes Deprecations ~~~~~~~~~~~~ - -- Deprecated passing ``nanoseconds`` greater than 999 or less than 0 in :class:`Timestamp` (:issue:`48538`, :issue:`48255`) +- .. --------------------------------------------------------------------------- .. _whatsnew_160.performance: diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index dd597f661a2cc..46e4c24d1fd6b 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -1692,17 +1692,12 @@ class Timestamp(_Timestamp): ) # Once this deprecation is enforced, we can do # return Timestamp(ts_input).tz_localize(tzobj) + if nanosecond is None: nanosecond = 0 elif not (999 >= nanosecond >= 0): - warnings.warn( - "In a future version, nanosecond must be between 0 and 999 inclusive " - "and will raise a ValueError otherwise. For nanoseconds > 999, " - "please distribute excess nanoseconds to microseconds and " - "other components as needed.", - FutureWarning, - stacklevel=find_stack_level(inspect.currentframe()), - ) + raise ValueError("nanosecond must be in 0..999") + ts = convert_to_tsobject(ts_input, tzobj, unit, 0, 0, nanosecond) if ts.value == NPY_NAT: diff --git a/pandas/tests/scalar/timestamp/test_constructors.py b/pandas/tests/scalar/timestamp/test_constructors.py index b8166438b78c1..58150fdce8503 100644 --- a/pandas/tests/scalar/timestamp/test_constructors.py +++ b/pandas/tests/scalar/timestamp/test_constructors.py @@ -680,7 +680,7 @@ def test_constructor_missing_keyword(kwargs): @pytest.mark.parametrize("nano", [-1, 1000]) -def test_timestamp_nano_range_deprecated(nano): +def test_timestamp_nano_range(nano): # GH 48255 - with tm.assert_produces_warning(FutureWarning): + with pytest.raises(ValueError, match="nanosecond must be in 0..999"): Timestamp(year=2022, month=1, day=1, nanosecond=nano)