From 49ea3fb062dc3d3b6e48df6143ea38b058e86a4a Mon Sep 17 00:00:00 2001 From: joooeey Date: Fri, 5 Aug 2022 20:19:11 +0200 Subject: [PATCH 01/18] added tests --- doc/source/reference/testing.rst | 1 + pandas/core/arrays/datetimes.py | 3 ++- pandas/errors/__init__.py | 7 +++++++ pandas/tests/indexes/period/test_constructors.py | 10 ++++++++++ pandas/tests/resample/test_period_index.py | 9 +++++++-- pandas/tests/scalar/timestamp/test_timestamp.py | 7 +++++-- 6 files changed, 32 insertions(+), 5 deletions(-) diff --git a/doc/source/reference/testing.rst b/doc/source/reference/testing.rst index 338dd87aa8c62..1fe5d6108534e 100644 --- a/doc/source/reference/testing.rst +++ b/doc/source/reference/testing.rst @@ -31,6 +31,7 @@ Exceptions and warnings errors.CSSWarning errors.DatabaseError errors.DataError + errors.DateTimeWarning errors.DtypeWarning errors.DuplicateLabelError errors.EmptyDataError diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index ffd093b86582c..5ef10c09ec105 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -41,6 +41,7 @@ ) from pandas._typing import npt from pandas.errors import ( + DateTimeWarning, OutOfBoundsDatetime, PerformanceWarning, ) @@ -1097,7 +1098,7 @@ def to_period(self, freq=None) -> PeriodArray: warnings.warn( "Converting to PeriodArray/Index representation " "will drop timezone information.", - UserWarning, + DateTimeWarning, ) if freq is None: diff --git a/pandas/errors/__init__.py b/pandas/errors/__init__.py index d7f5e7aab58ab..829ad15b36529 100644 --- a/pandas/errors/__init__.py +++ b/pandas/errors/__init__.py @@ -479,6 +479,12 @@ class DatabaseError(OSError): """ +class DateTimeWarning(UserWarning): + """ + Warning raised for issues with interpreting dates and times. + """ + + __all__ = [ "AbstractMethodError", "AccessorRegistrationWarning", @@ -487,6 +493,7 @@ class DatabaseError(OSError): "CSSWarning", "DatabaseError", "DataError", + "DateTimeWarning", "DtypeWarning", "DuplicateLabelError", "EmptyDataError", diff --git a/pandas/tests/indexes/period/test_constructors.py b/pandas/tests/indexes/period/test_constructors.py index 5dff5c2ad9c86..1435822f077cf 100644 --- a/pandas/tests/indexes/period/test_constructors.py +++ b/pandas/tests/indexes/period/test_constructors.py @@ -2,6 +2,7 @@ import pytest from pandas._libs.tslibs.period import IncompatibleFrequency +from pandas.errors import DateTimeWarning from pandas.core.dtypes.dtypes import PeriodDtype @@ -512,6 +513,15 @@ def test_map_with_string_constructor(self): # lastly, values should compare equal tm.assert_index_equal(res, expected) + def test_range_tz(self): + # GH 47005 Time zone should be ignored with warning. + with tm.assert_produces_warning(DateTimeWarning): + pi_tz = period_range( + "2022-01-01 06:00:00+02:00", "2022-01-01 09:00:00+02:00", freq="H" + ) + pi_naive = period_range("2022-01-01 06:00:00", "2022-01-01 09:00:00", freq="H") + tm.assert_index_equal(pi_tz, pi_naive) + class TestShallowCopy: def test_shallow_copy_empty(self): diff --git a/pandas/tests/resample/test_period_index.py b/pandas/tests/resample/test_period_index.py index 4da1f4c589c56..9f29fadec77dd 100644 --- a/pandas/tests/resample/test_period_index.py +++ b/pandas/tests/resample/test_period_index.py @@ -10,7 +10,10 @@ MONTHS, ) from pandas._libs.tslibs.period import IncompatibleFrequency -from pandas.errors import InvalidIndexError +from pandas.errors import ( + DateTimeWarning, + InvalidIndexError, +) import pandas as pd from pandas import ( @@ -263,7 +266,9 @@ def test_with_local_timezone_pytz(self): series = Series(1, index=index) series = series.tz_convert(local_timezone) - result = series.resample("D", kind="period").mean() + # see gh-47005 + with tm.assert_produces_warning(DateTimeWarning): + result = series.resample("D", kind="period").mean() # Create the expected series # Index is moved back a day with the timezone conversion from UTC to diff --git a/pandas/tests/scalar/timestamp/test_timestamp.py b/pandas/tests/scalar/timestamp/test_timestamp.py index 67ad152dcab30..eb8505d1c7fba 100644 --- a/pandas/tests/scalar/timestamp/test_timestamp.py +++ b/pandas/tests/scalar/timestamp/test_timestamp.py @@ -25,7 +25,10 @@ maybe_get_tz, tz_compare, ) -from pandas.errors import OutOfBoundsDatetime +from pandas.errors import ( + DateTimeWarning, + OutOfBoundsDatetime, +) import pandas.util._test_decorators as td from pandas import ( @@ -661,7 +664,7 @@ def test_to_period_tz_warning(self): # GH#21333 make sure a warning is issued when timezone # info is lost ts = Timestamp("2009-04-15 16:17:18", tz="US/Eastern") - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(DateTimeWarning): # warning that timezone info will be lost ts.to_period("D") From d949d60118ff9ead38ddb871d453f1076f672a21 Mon Sep 17 00:00:00 2001 From: joooeey Date: Sat, 6 Aug 2022 14:16:56 +0200 Subject: [PATCH 02/18] insert warning --- doc/source/whatsnew/v1.4.4.rst | 1 + pandas/_libs/tslibs/period.pyx | 9 +++++++++ pandas/tests/indexes/period/test_period_range.py | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.4.4.rst b/doc/source/whatsnew/v1.4.4.rst index a49772fb83ca7..93d1244b24cbc 100644 --- a/doc/source/whatsnew/v1.4.4.rst +++ b/doc/source/whatsnew/v1.4.4.rst @@ -29,6 +29,7 @@ Bug fixes - Bug in :meth:`DataFrame.to_sql` when ``method`` was a ``callable`` that did not return an ``int`` and would raise a ``TypeError`` (:issue:`46891`) - Bug in :func:`read_xml` when reading XML files with Chinese character tags and would raise ``XMLSyntaxError`` (:issue:`47902`) - Bug in :meth:`loc.__getitem__` with a list of keys causing an internal inconsistency that could lead to a disconnect between ``frame.at[x, y]`` vs ``frame[y].loc[x]`` (:issue:`22372`) +- :class:`Period` now raises a warning when created with data that contains timezone information. This is necessary because :class:`Period`, :class:`PeriodArray` and :class:`PeriodIndex` do not support timezones and hence drop any timezone information used when creating them. (:issue:`47005`) .. --------------------------------------------------------------------------- diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index fa264f29aa8a8..c2720ff4e6560 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -1,5 +1,7 @@ import warnings +from pandas.errors import DateTimeWarning + cimport numpy as cnp from cpython.object cimport ( Py_EQ, @@ -2585,6 +2587,13 @@ class Period(_Period): reso = 'nanosecond' if dt is NaT: ordinal = NPY_NAT + elif dt.tzinfo: + # GH 47005 + warnings.warn( + "The pandas.Period class does not support timezones. " + "The timezone given in '%s' will be ignored." % value, + DateTimeWarning + ) if freq is None: try: diff --git a/pandas/tests/indexes/period/test_period_range.py b/pandas/tests/indexes/period/test_period_range.py index c94ddf57c0ee1..42480a4d81ee2 100644 --- a/pandas/tests/indexes/period/test_period_range.py +++ b/pandas/tests/indexes/period/test_period_range.py @@ -20,7 +20,7 @@ def test_required_arguments(self): with pytest.raises(ValueError, match=msg): period_range("2011-1-1", "2012-1-1", "B") - @pytest.mark.parametrize("freq", ["D", "W", "M", "Q", "A"]) + @pytest.mark.parametrize("freq", ["D", "M", "Q", "A"]) def test_construction_from_string(self, freq): # non-empty expected = date_range( From cd421e44de60f8d27779b789cf0d63b64d565a8a Mon Sep 17 00:00:00 2001 From: joooeey Date: Sat, 6 Aug 2022 15:12:15 +0200 Subject: [PATCH 03/18] test for Period itself added. --- pandas/tests/indexes/period/test_constructors.py | 10 ---------- pandas/tests/indexes/period/test_period_range.py | 12 ++++++++++++ pandas/tests/scalar/period/test_period.py | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/pandas/tests/indexes/period/test_constructors.py b/pandas/tests/indexes/period/test_constructors.py index 1435822f077cf..5dff5c2ad9c86 100644 --- a/pandas/tests/indexes/period/test_constructors.py +++ b/pandas/tests/indexes/period/test_constructors.py @@ -2,7 +2,6 @@ import pytest from pandas._libs.tslibs.period import IncompatibleFrequency -from pandas.errors import DateTimeWarning from pandas.core.dtypes.dtypes import PeriodDtype @@ -513,15 +512,6 @@ def test_map_with_string_constructor(self): # lastly, values should compare equal tm.assert_index_equal(res, expected) - def test_range_tz(self): - # GH 47005 Time zone should be ignored with warning. - with tm.assert_produces_warning(DateTimeWarning): - pi_tz = period_range( - "2022-01-01 06:00:00+02:00", "2022-01-01 09:00:00+02:00", freq="H" - ) - pi_naive = period_range("2022-01-01 06:00:00", "2022-01-01 09:00:00", freq="H") - tm.assert_index_equal(pi_tz, pi_naive) - class TestShallowCopy: def test_shallow_copy_empty(self): diff --git a/pandas/tests/indexes/period/test_period_range.py b/pandas/tests/indexes/period/test_period_range.py index 42480a4d81ee2..036c8b9b1cc33 100644 --- a/pandas/tests/indexes/period/test_period_range.py +++ b/pandas/tests/indexes/period/test_period_range.py @@ -1,6 +1,8 @@ import numpy as np import pytest +from pandas.errors import DateTimeWarning + from pandas import ( NaT, Period, @@ -119,3 +121,13 @@ def test_errors(self): msg = "periods must be a number, got foo" with pytest.raises(TypeError, match=msg): period_range(start="2017Q1", periods="foo") + + +def test_range_tz(): + # GH 47005 Time zone should be ignored with warning. + with tm.assert_produces_warning(DateTimeWarning): + pi_tz = period_range( + "2022-01-01 06:00:00+02:00", "2022-01-01 09:00:00+02:00", freq="H" + ) + pi_naive = period_range("2022-01-01 06:00:00", "2022-01-01 09:00:00", freq="H") + tm.assert_index_equal(pi_tz, pi_naive) diff --git a/pandas/tests/scalar/period/test_period.py b/pandas/tests/scalar/period/test_period.py index 20d6b9e77a034..5e73c9b85dacf 100644 --- a/pandas/tests/scalar/period/test_period.py +++ b/pandas/tests/scalar/period/test_period.py @@ -26,6 +26,7 @@ dateutil_gettz, maybe_get_tz, ) +from pandas.errors import DateTimeWarning import pandas as pd from pandas import ( @@ -1616,3 +1617,18 @@ def test_invalid_frequency_error_message(): msg = "Invalid frequency: " with pytest.raises(ValueError, match=msg): Period("2012-01-02", freq="WOM-1MON") + + +@pytest.mark.parametrize( + "val", + [ + ("20220101T123456", "Z"), + ("2012-12-12T06:06:06", "-06:00"), + ], +) +def test_period_with_timezone(val): + # GH 47005 Time zone should be ignored with warning. + with tm.assert_produces_warning(DateTimeWarning): + p_tz = Period("".join(val), freq="s") + p_naive = Period(val[0], freq="s") + assert p_tz == p_naive From 5d99f754cda20f4b1cb417338f194749e2e29a98 Mon Sep 17 00:00:00 2001 From: joooeey Date: Sat, 6 Aug 2022 16:15:34 +0200 Subject: [PATCH 04/18] Replace DateTimeWarning by UserWarning --- pandas/_libs/tslibs/period.pyx | 4 +--- pandas/core/arrays/datetimes.py | 3 +-- pandas/errors/__init__.py | 7 ------- pandas/tests/indexes/period/test_period_range.py | 4 +--- pandas/tests/resample/test_period_index.py | 7 ++----- pandas/tests/scalar/period/test_period.py | 3 +-- pandas/tests/scalar/timestamp/test_timestamp.py | 7 ++----- 7 files changed, 8 insertions(+), 27 deletions(-) diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index c2720ff4e6560..963b2e1765b83 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -1,7 +1,5 @@ import warnings -from pandas.errors import DateTimeWarning - cimport numpy as cnp from cpython.object cimport ( Py_EQ, @@ -2592,7 +2590,7 @@ class Period(_Period): warnings.warn( "The pandas.Period class does not support timezones. " "The timezone given in '%s' will be ignored." % value, - DateTimeWarning + UserWarning ) if freq is None: diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index 5ef10c09ec105..ffd093b86582c 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -41,7 +41,6 @@ ) from pandas._typing import npt from pandas.errors import ( - DateTimeWarning, OutOfBoundsDatetime, PerformanceWarning, ) @@ -1098,7 +1097,7 @@ def to_period(self, freq=None) -> PeriodArray: warnings.warn( "Converting to PeriodArray/Index representation " "will drop timezone information.", - DateTimeWarning, + UserWarning, ) if freq is None: diff --git a/pandas/errors/__init__.py b/pandas/errors/__init__.py index 829ad15b36529..d7f5e7aab58ab 100644 --- a/pandas/errors/__init__.py +++ b/pandas/errors/__init__.py @@ -479,12 +479,6 @@ class DatabaseError(OSError): """ -class DateTimeWarning(UserWarning): - """ - Warning raised for issues with interpreting dates and times. - """ - - __all__ = [ "AbstractMethodError", "AccessorRegistrationWarning", @@ -493,7 +487,6 @@ class DateTimeWarning(UserWarning): "CSSWarning", "DatabaseError", "DataError", - "DateTimeWarning", "DtypeWarning", "DuplicateLabelError", "EmptyDataError", diff --git a/pandas/tests/indexes/period/test_period_range.py b/pandas/tests/indexes/period/test_period_range.py index 036c8b9b1cc33..b9e6afe769829 100644 --- a/pandas/tests/indexes/period/test_period_range.py +++ b/pandas/tests/indexes/period/test_period_range.py @@ -1,8 +1,6 @@ import numpy as np import pytest -from pandas.errors import DateTimeWarning - from pandas import ( NaT, Period, @@ -125,7 +123,7 @@ def test_errors(self): def test_range_tz(): # GH 47005 Time zone should be ignored with warning. - with tm.assert_produces_warning(DateTimeWarning): + with tm.assert_produces_warning(UserWarning): pi_tz = period_range( "2022-01-01 06:00:00+02:00", "2022-01-01 09:00:00+02:00", freq="H" ) diff --git a/pandas/tests/resample/test_period_index.py b/pandas/tests/resample/test_period_index.py index 9f29fadec77dd..2aec6727d44df 100644 --- a/pandas/tests/resample/test_period_index.py +++ b/pandas/tests/resample/test_period_index.py @@ -10,10 +10,7 @@ MONTHS, ) from pandas._libs.tslibs.period import IncompatibleFrequency -from pandas.errors import ( - DateTimeWarning, - InvalidIndexError, -) +from pandas.errors import InvalidIndexError import pandas as pd from pandas import ( @@ -267,7 +264,7 @@ def test_with_local_timezone_pytz(self): series = Series(1, index=index) series = series.tz_convert(local_timezone) # see gh-47005 - with tm.assert_produces_warning(DateTimeWarning): + with tm.assert_produces_warning(UserWarning): result = series.resample("D", kind="period").mean() # Create the expected series diff --git a/pandas/tests/scalar/period/test_period.py b/pandas/tests/scalar/period/test_period.py index 5e73c9b85dacf..9c18fe142d6a1 100644 --- a/pandas/tests/scalar/period/test_period.py +++ b/pandas/tests/scalar/period/test_period.py @@ -26,7 +26,6 @@ dateutil_gettz, maybe_get_tz, ) -from pandas.errors import DateTimeWarning import pandas as pd from pandas import ( @@ -1628,7 +1627,7 @@ def test_invalid_frequency_error_message(): ) def test_period_with_timezone(val): # GH 47005 Time zone should be ignored with warning. - with tm.assert_produces_warning(DateTimeWarning): + with tm.assert_produces_warning(UserWarning): p_tz = Period("".join(val), freq="s") p_naive = Period(val[0], freq="s") assert p_tz == p_naive diff --git a/pandas/tests/scalar/timestamp/test_timestamp.py b/pandas/tests/scalar/timestamp/test_timestamp.py index eb8505d1c7fba..67ad152dcab30 100644 --- a/pandas/tests/scalar/timestamp/test_timestamp.py +++ b/pandas/tests/scalar/timestamp/test_timestamp.py @@ -25,10 +25,7 @@ maybe_get_tz, tz_compare, ) -from pandas.errors import ( - DateTimeWarning, - OutOfBoundsDatetime, -) +from pandas.errors import OutOfBoundsDatetime import pandas.util._test_decorators as td from pandas import ( @@ -664,7 +661,7 @@ def test_to_period_tz_warning(self): # GH#21333 make sure a warning is issued when timezone # info is lost ts = Timestamp("2009-04-15 16:17:18", tz="US/Eastern") - with tm.assert_produces_warning(DateTimeWarning): + with tm.assert_produces_warning(UserWarning): # warning that timezone info will be lost ts.to_period("D") From 8de04d17e4ec694266dfa17ee77dcbe967a1d369 Mon Sep 17 00:00:00 2001 From: joooeey Date: Sat, 6 Aug 2022 16:41:01 +0200 Subject: [PATCH 05/18] Removed overlooked DateTimeWarning from testing.rst. --- doc/source/reference/testing.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/source/reference/testing.rst b/doc/source/reference/testing.rst index 1fe5d6108534e..338dd87aa8c62 100644 --- a/doc/source/reference/testing.rst +++ b/doc/source/reference/testing.rst @@ -31,7 +31,6 @@ Exceptions and warnings errors.CSSWarning errors.DatabaseError errors.DataError - errors.DateTimeWarning errors.DtypeWarning errors.DuplicateLabelError errors.EmptyDataError From a067f8428b9fceed94020260a7952ff52980203c Mon Sep 17 00:00:00 2001 From: joooeey Date: Sat, 6 Aug 2022 21:44:17 +0200 Subject: [PATCH 06/18] Added warning for Period creation with timestamp. Suppressed warning in matplotlib. --- pandas/_libs/tslibs/period.pyx | 14 ++++----- pandas/plotting/_matplotlib/converter.py | 5 ++- pandas/tests/arrays/test_datetimelike.py | 2 +- .../datetimes/methods/test_to_period.py | 16 ++++++---- pandas/tests/resample/test_period_index.py | 31 ++++++++++++------- 5 files changed, 41 insertions(+), 27 deletions(-) diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index 963b2e1765b83..1f2e21499a4ef 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -2585,13 +2585,6 @@ class Period(_Period): reso = 'nanosecond' if dt is NaT: ordinal = NPY_NAT - elif dt.tzinfo: - # GH 47005 - warnings.warn( - "The pandas.Period class does not support timezones. " - "The timezone given in '%s' will be ignored." % value, - UserWarning - ) if freq is None: try: @@ -2621,6 +2614,13 @@ class Period(_Period): raise ValueError(msg) if ordinal is None: + if dt.tzinfo: + # GH 47005 + warnings.warn( + "The pandas.Period class does not support timezones. " + "The timezone given in '%s' will be ignored." % value, + UserWarning + ) base = freq_to_dtype_code(freq) ordinal = period_ordinal(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, diff --git a/pandas/plotting/_matplotlib/converter.py b/pandas/plotting/_matplotlib/converter.py index 8510a7acac117..bde5f83e37f4a 100644 --- a/pandas/plotting/_matplotlib/converter.py +++ b/pandas/plotting/_matplotlib/converter.py @@ -14,6 +14,7 @@ Iterator, cast, ) +import warnings from dateutil.relativedelta import relativedelta import matplotlib.dates as dates @@ -261,7 +262,9 @@ def get_datevalue(date, freq): if isinstance(date, Period): return date.asfreq(freq).ordinal elif isinstance(date, (str, datetime, pydt.date, pydt.time, np.datetime64)): - return Period(date, freq).ordinal + with warnings.catch_warnings(): + warnings.simplefilter("ignore", UserWarning) + return Period(date, freq).ordinal elif ( is_integer(date) or is_float(date) diff --git a/pandas/tests/arrays/test_datetimelike.py b/pandas/tests/arrays/test_datetimelike.py index ea895e5656ccb..61d377d2054ec 100644 --- a/pandas/tests/arrays/test_datetimelike.py +++ b/pandas/tests/arrays/test_datetimelike.py @@ -1070,7 +1070,7 @@ class TestPeriodArray(SharedTests): index_cls = PeriodIndex array_cls = PeriodArray scalar_type = Period - example_dtype = PeriodIndex([], freq="W").dtype + example_dtype = PeriodIndex([], freq="Q").dtype @pytest.fixture def arr1d(self, period_index): diff --git a/pandas/tests/indexes/datetimes/methods/test_to_period.py b/pandas/tests/indexes/datetimes/methods/test_to_period.py index f6a598bd2a1ed..bd47f224347be 100644 --- a/pandas/tests/indexes/datetimes/methods/test_to_period.py +++ b/pandas/tests/indexes/datetimes/methods/test_to_period.py @@ -117,11 +117,13 @@ def test_to_period_millisecond(self): ) with tm.assert_produces_warning(UserWarning): - # warning that timezone info will be lost + # GH 21333 - warning that timezone info will be lost period = index.to_period(freq="L") assert 2 == len(period) - assert period[0] == Period("2007-01-01 10:11:12.123Z", "L") - assert period[1] == Period("2007-01-01 10:11:13.789Z", "L") + with tm.assert_produces_warning(UserWarning): + # GH 47005 - warning that timezone info will be lost + assert period[0] == Period("2007-01-01 10:11:12.123Z", "L") + assert period[1] == Period("2007-01-01 10:11:13.789Z", "L") def test_to_period_microsecond(self): index = DatetimeIndex( @@ -132,11 +134,13 @@ def test_to_period_microsecond(self): ) with tm.assert_produces_warning(UserWarning): - # warning that timezone info will be lost + # GH 21333 - warning that timezone info will be lost period = index.to_period(freq="U") assert 2 == len(period) - assert period[0] == Period("2007-01-01 10:11:12.123456Z", "U") - assert period[1] == Period("2007-01-01 10:11:13.789123Z", "U") + with tm.assert_produces_warning(UserWarning): + # GH 47005 - warning that timezone info will be lost + assert period[0] == Period("2007-01-01 10:11:12.123456Z", "U") + assert period[1] == Period("2007-01-01 10:11:13.789123Z", "U") @pytest.mark.parametrize( "tz", diff --git a/pandas/tests/resample/test_period_index.py b/pandas/tests/resample/test_period_index.py index 2aec6727d44df..4baa1ddc2f307 100644 --- a/pandas/tests/resample/test_period_index.py +++ b/pandas/tests/resample/test_period_index.py @@ -267,10 +267,12 @@ def test_with_local_timezone_pytz(self): with tm.assert_produces_warning(UserWarning): result = series.resample("D", kind="period").mean() - # Create the expected series - # Index is moved back a day with the timezone conversion from UTC to - # Pacific - expected_index = period_range(start=start, end=end, freq="D") - offsets.Day() + # Create the expected series + # Index is moved back a day with the timezone conversion from UTC to + # Pacific + expected_index = ( + period_range(start=start, end=end, freq="D") - offsets.Day() + ) expected = Series(1.0, index=expected_index) tm.assert_series_equal(result, expected) @@ -306,14 +308,16 @@ def test_with_local_timezone_dateutil(self): series = Series(1, index=index) series = series.tz_convert(local_timezone) - result = series.resample("D", kind="period").mean() + # see gh-47005 + with tm.assert_produces_warning(UserWarning): + result = series.resample("D", kind="period").mean() - # Create the expected series - # Index is moved back a day with the timezone conversion from UTC to - # Pacific - expected_index = ( - period_range(start=start, end=end, freq="D", name="idx") - offsets.Day() - ) + # Create the expected series + # Index is moved back a day with the timezone conversion from UTC to + # Pacific + expected_index = ( + period_range(start=start, end=end, freq="D", name="idx") - offsets.Day() + ) expected = Series(1.0, index=expected_index) tm.assert_series_equal(result, expected) @@ -506,7 +510,10 @@ def test_resample_tz_localized(self): tm.assert_series_equal(result, expected) # for good measure - result = s.resample("D", kind="period").mean() + # see gh-47005 + with tm.assert_produces_warning(UserWarning): + result = s.resample("D", kind="period").mean() + ex_index = period_range("2001-09-20", periods=1, freq="D") expected = Series([1.5], index=ex_index) tm.assert_series_equal(result, expected) From 57d8883cf2f48ea18f69c31f6ab9e5e8d1f5e6d0 Mon Sep 17 00:00:00 2001 From: joooeey Date: Sat, 6 Aug 2022 23:25:44 +0200 Subject: [PATCH 07/18] Suppress warning when indexing dataframe with string datetimes. --- pandas/core/indexes/datetimes.py | 6 +++++- pandas/tests/indexing/test_datetime.py | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index 30c770f32c2dc..531826bf11ee1 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -616,7 +616,11 @@ def _parsed_string_to_bounds(self, reso: Resolution, parsed: datetime): ------- lower, upper: pd.Timestamp """ - per = Period(parsed, freq=reso.attr_abbrev) + with warnings.catch_warnings(): + # Period looses tzinfo. We ignore the corresponding warning here, + # and add the lost tzinfo below. + warnings.simplefilter("ignore", UserWarning) + per = Period(parsed, freq=reso.attr_abbrev) start, end = per.start_time, per.end_time # GH 24076 diff --git a/pandas/tests/indexing/test_datetime.py b/pandas/tests/indexing/test_datetime.py index 8d498b59c55d1..d9dfe80ecfd2e 100644 --- a/pandas/tests/indexing/test_datetime.py +++ b/pandas/tests/indexing/test_datetime.py @@ -168,3 +168,11 @@ def test_getitem_str_slice_millisecond_resolution(self, frame_or_series): ], ) tm.assert_equal(result, expected) + + +def test_slice_with_datestring_tz(): + # GH 24076 + # GH 16785 + df = DataFrame([0], index=pd.DatetimeIndex(["2019-01-01"], tz="US/Pacific")) + sliced = df["2019-01-01 12:00:00+04:00":"2019-01-01 13:00:00+04:00"] + tm.assert_frame_equal(sliced, df) From b9e119efecd8e928cb9801ea90a7532fd38aa2ff Mon Sep 17 00:00:00 2001 From: joooeey Date: Tue, 9 Aug 2022 18:53:04 +0200 Subject: [PATCH 08/18] warn with f-string instead of % --- pandas/_libs/tslibs/period.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index 1f2e21499a4ef..025a699d6a873 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -2618,7 +2618,7 @@ class Period(_Period): # GH 47005 warnings.warn( "The pandas.Period class does not support timezones. " - "The timezone given in '%s' will be ignored." % value, + f"The timezone given in '{value}' will be ignored.", UserWarning ) base = freq_to_dtype_code(freq) From edf7de3eef440ebcfd7a7e9ae0f99bb24bac7214 Mon Sep 17 00:00:00 2001 From: joooeey Date: Tue, 13 Dec 2022 21:20:50 +0100 Subject: [PATCH 09/18] move changelog to correct .rst (part 1) --- doc/source/whatsnew/v1.4.4.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/source/whatsnew/v1.4.4.rst b/doc/source/whatsnew/v1.4.4.rst index e1448546cd999..56b1254d8a359 100644 --- a/doc/source/whatsnew/v1.4.4.rst +++ b/doc/source/whatsnew/v1.4.4.rst @@ -46,7 +46,6 @@ Bug fixes - Bug in :meth:`.DataFrameGroupBy.value_counts` where ``subset`` had no effect (:issue:`46383`) - Bug when getting values with :meth:`DataFrame.loc` with a list of keys causing an internal inconsistency that could lead to a disconnect between ``frame.at[x, y]`` vs ``frame[y].loc[x]`` (:issue:`22372`) - Bug in the :meth:`Series.dt.strftime` accessor return a float instead of object dtype Series for all-NaT input, which also causes a spurious deprecation warning (:issue:`45858`) -- :class:`Period` now raises a warning when created with data that contains timezone information. This is necessary because :class:`Period`, :class:`PeriodArray` and :class:`PeriodIndex` do not support timezones and hence drop any timezone information used when creating them. (:issue:`47005`) .. --------------------------------------------------------------------------- From 4d8ee9b8a5484ba0c738b849586656a5f7171a34 Mon Sep 17 00:00:00 2001 From: joooeey Date: Tue, 13 Dec 2022 21:24:01 +0100 Subject: [PATCH 10/18] move whatsnew bullet to v1.5.3.rst --- doc/source/whatsnew/v1.5.3.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.5.3.rst b/doc/source/whatsnew/v1.5.3.rst index 581d28e10bd67..ab80e21e9adce 100644 --- a/doc/source/whatsnew/v1.5.3.rst +++ b/doc/source/whatsnew/v1.5.3.rst @@ -29,6 +29,7 @@ Bug fixes - Bug in :meth:`.Styler.to_excel` leading to error when unrecognized ``border-style`` (e.g. ``"hair"``) provided to Excel writers (:issue:`48649`) - Bug when chaining several :meth:`.Styler.concat` calls, only the last styler was concatenated (:issue:`49207`) - Fixed bug when instantiating a :class:`DataFrame` subclass inheriting from ``typing.Generic`` that triggered a ``UserWarning`` on python 3.11 (:issue:`49649`) +- :class:`Period` now raises a warning when created with data that contains timezone information. This is necessary because :class:`Period`, :class:`PeriodArray` and :class:`PeriodIndex` do not support timezones and hence drop any timezone information used when creating them. (:issue:`47005`) - .. --------------------------------------------------------------------------- From ca24736efb80576e0485644b0dd64497ba291fbf Mon Sep 17 00:00:00 2001 From: joooeey Date: Tue, 13 Dec 2022 21:37:38 +0100 Subject: [PATCH 11/18] re-introduce test for week period --- pandas/tests/indexes/period/test_period_range.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pandas/tests/indexes/period/test_period_range.py b/pandas/tests/indexes/period/test_period_range.py index b9e6afe769829..0fb3b27e384dc 100644 --- a/pandas/tests/indexes/period/test_period_range.py +++ b/pandas/tests/indexes/period/test_period_range.py @@ -20,7 +20,16 @@ def test_required_arguments(self): with pytest.raises(ValueError, match=msg): period_range("2011-1-1", "2012-1-1", "B") - @pytest.mark.parametrize("freq", ["D", "M", "Q", "A"]) + @pytest.mark.parametrize( + "freq", + [ + "D", + pytest.param("W", marks=pytest.mark.filterwarnings("ignore:.*timezone")), + "M", + "Q", + "A", + ] + ) def test_construction_from_string(self, freq): # non-empty expected = date_range( From d398265195c03952bdf4a9f6d84d4b5bc60115a0 Mon Sep 17 00:00:00 2001 From: joooeey Date: Tue, 13 Dec 2022 21:47:26 +0100 Subject: [PATCH 12/18] Fix broken merge (missing import) --- pandas/_libs/tslibs/period.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index 317c20e13a215..23c4629d757f2 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -1,3 +1,5 @@ +import warnings + cimport numpy as cnp from cpython.object cimport ( Py_EQ, From 84621a0920ff87bfabc67608f864d1df9be7759f Mon Sep 17 00:00:00 2001 From: joooeey Date: Tue, 13 Dec 2022 22:12:19 +0100 Subject: [PATCH 13/18] black --- pandas/tests/indexes/period/test_period_range.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/indexes/period/test_period_range.py b/pandas/tests/indexes/period/test_period_range.py index 0fb3b27e384dc..9e62c661b66f0 100644 --- a/pandas/tests/indexes/period/test_period_range.py +++ b/pandas/tests/indexes/period/test_period_range.py @@ -28,7 +28,7 @@ def test_required_arguments(self): "M", "Q", "A", - ] + ], ) def test_construction_from_string(self, freq): # non-empty From 55fbbab6d8f7168be4de65b70c44d8182dccfff0 Mon Sep 17 00:00:00 2001 From: joooeey Date: Tue, 13 Dec 2022 23:11:58 +0100 Subject: [PATCH 14/18] increment warning stacklevel --- pandas/_libs/tslibs/period.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index 23c4629d757f2..2662ffd99e4ce 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -2620,7 +2620,8 @@ class Period(_Period): warnings.warn( "The pandas.Period class does not support timezones. " f"The timezone given in '{value}' will be ignored.", - UserWarning + UserWarning, + stacklevel=2 ) base = freq_to_dtype_code(freq) ordinal = period_ordinal(dt.year, dt.month, dt.day, From 441d17c29c1dbd6144e0f702e2d12e795b659e8e Mon Sep 17 00:00:00 2001 From: joooeey Date: Wed, 14 Dec 2022 09:11:32 +0100 Subject: [PATCH 15/18] revert stacklevel change --- pandas/_libs/tslibs/period.pyx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index 2662ffd99e4ce..23c4629d757f2 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -2620,8 +2620,7 @@ class Period(_Period): warnings.warn( "The pandas.Period class does not support timezones. " f"The timezone given in '{value}' will be ignored.", - UserWarning, - stacklevel=2 + UserWarning ) base = freq_to_dtype_code(freq) ordinal = period_ordinal(dt.year, dt.month, dt.day, From abf431e964a398caf8de8603da8acd340144a210 Mon Sep 17 00:00:00 2001 From: joooeey Date: Wed, 14 Dec 2022 09:12:35 +0100 Subject: [PATCH 16/18] remove stacklevel check I couldn't pin down why the tests think, the stacklevel is wrong. In the stock python interpreter, the warning message refers to the correct line. --- pandas/tests/indexes/period/test_period_range.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/indexes/period/test_period_range.py b/pandas/tests/indexes/period/test_period_range.py index 9e62c661b66f0..4c56a5b4750e8 100644 --- a/pandas/tests/indexes/period/test_period_range.py +++ b/pandas/tests/indexes/period/test_period_range.py @@ -132,7 +132,7 @@ def test_errors(self): def test_range_tz(): # GH 47005 Time zone should be ignored with warning. - with tm.assert_produces_warning(UserWarning): + with tm.assert_produces_warning(UserWarning, check_stacklevel=False): pi_tz = period_range( "2022-01-01 06:00:00+02:00", "2022-01-01 09:00:00+02:00", freq="H" ) From cecc73888db416b17c1d0813252dbcd2d61e8c4c Mon Sep 17 00:00:00 2001 From: joooeey Date: Wed, 14 Dec 2022 22:35:02 +0100 Subject: [PATCH 17/18] re-include stacklevel check --- pandas/tests/indexes/period/test_period_range.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/indexes/period/test_period_range.py b/pandas/tests/indexes/period/test_period_range.py index 4c56a5b4750e8..9e62c661b66f0 100644 --- a/pandas/tests/indexes/period/test_period_range.py +++ b/pandas/tests/indexes/period/test_period_range.py @@ -132,7 +132,7 @@ def test_errors(self): def test_range_tz(): # GH 47005 Time zone should be ignored with warning. - with tm.assert_produces_warning(UserWarning, check_stacklevel=False): + with tm.assert_produces_warning(UserWarning): pi_tz = period_range( "2022-01-01 06:00:00+02:00", "2022-01-01 09:00:00+02:00", freq="H" ) From b5a2b8eed7c2a3d67920c29bc91c888dad082e2b Mon Sep 17 00:00:00 2001 From: joooeey Date: Wed, 14 Dec 2022 22:55:00 +0100 Subject: [PATCH 18/18] Add comment with reference to GitHub issue. --- pandas/tests/indexes/period/test_period_range.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/tests/indexes/period/test_period_range.py b/pandas/tests/indexes/period/test_period_range.py index 9e62c661b66f0..15334ca2e8c53 100644 --- a/pandas/tests/indexes/period/test_period_range.py +++ b/pandas/tests/indexes/period/test_period_range.py @@ -24,6 +24,7 @@ def test_required_arguments(self): "freq", [ "D", + # Parsing week strings is not fully supported. See GH 48000. pytest.param("W", marks=pytest.mark.filterwarnings("ignore:.*timezone")), "M", "Q",