diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index dc05745c8c0e5..657f1d1fb84e6 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -611,6 +611,7 @@ Other API changes Deprecations ~~~~~~~~~~~~ +- Deprecated parsing datetime strings with system-local timezone to ``tzlocal``, pass a ``tz`` keyword or explicitly call ``tz_localize`` instead (:issue:`50791`) - Deprecated argument ``infer_datetime_format`` in :func:`to_datetime` and :func:`read_csv`, as a strict version of it is now the default (:issue:`48621`) - Deprecated :func:`pandas.io.sql.execute` (:issue:`50185`) - :meth:`Index.is_boolean` has been deprecated. Use :func:`pandas.api.types.is_bool_dtype` instead (:issue:`50042`) diff --git a/pandas/_libs/tslibs/parsing.pyx b/pandas/_libs/tslibs/parsing.pyx index aa53f8d813874..485813a634f20 100644 --- a/pandas/_libs/tslibs/parsing.pyx +++ b/pandas/_libs/tslibs/parsing.pyx @@ -653,6 +653,18 @@ cdef dateutil_parse( ret = ret + relativedelta.relativedelta(weekday=res.weekday) if not ignoretz: if res.tzname and res.tzname in time.tzname: + # GH#50791 + if res.tzname != "UTC": + # If the system is localized in UTC (as many CI runs are) + # we get tzlocal, once the deprecation is enforced will get + # timezone.utc, not raise. + warnings.warn( + "Parsing '{res.tzname}' as tzlocal (dependent on system timezone) " + "is deprecated and will raise in a future version. Pass the 'tz' " + "keyword or call tz_localize after construction instead", + FutureWarning, + stacklevel=find_stack_level() + ) ret = ret.replace(tzinfo=_dateutil_tzlocal()) elif res.tzoffset == 0: ret = ret.replace(tzinfo=_dateutil_tzutc()) diff --git a/pandas/tests/tslibs/test_array_to_datetime.py b/pandas/tests/tslibs/test_array_to_datetime.py index 63adb8427969d..ba188c3182f57 100644 --- a/pandas/tests/tslibs/test_array_to_datetime.py +++ b/pandas/tests/tslibs/test_array_to_datetime.py @@ -71,7 +71,9 @@ def test_parsing_non_iso_timezone_offset(): dt_string = "01-01-2013T00:00:00.000000000+0000" arr = np.array([dt_string], dtype=object) - result, result_tz = tslib.array_to_datetime(arr) + with tm.assert_produces_warning(None): + # GH#50949 should not get tzlocal-deprecation warning here + result, result_tz = tslib.array_to_datetime(arr) expected = np.array([np.datetime64("2013-01-01 00:00:00.000000000")]) tm.assert_numpy_array_equal(result, expected) diff --git a/pandas/tests/tslibs/test_parsing.py b/pandas/tests/tslibs/test_parsing.py index 33fce7b351513..b0f7f755518a4 100644 --- a/pandas/tests/tslibs/test_parsing.py +++ b/pandas/tests/tslibs/test_parsing.py @@ -5,6 +5,7 @@ import re from dateutil.parser import parse as du_parse +from dateutil.tz import tzlocal import numpy as np import pytest @@ -18,6 +19,23 @@ import pandas._testing as tm +@td.skip_if_windows +def test_parsing_tzlocal_deprecated(): + # GH#50791 + msg = "Pass the 'tz' keyword or call tz_localize after construction instead" + dtstr = "Jan 15 2004 03:00 EST" + + with tm.set_timezone("US/Eastern"): + with tm.assert_produces_warning(FutureWarning, match=msg): + res, _ = parse_datetime_string_with_reso(dtstr) + + assert isinstance(res.tzinfo, tzlocal) + + with tm.assert_produces_warning(FutureWarning, match=msg): + res = parsing.parse_datetime_string(dtstr) + assert isinstance(res.tzinfo, tzlocal) + + def test_parse_datetime_string_with_reso(): (parsed, reso) = parse_datetime_string_with_reso("4Q1984") (parsed_lower, reso_lower) = parse_datetime_string_with_reso("4q1984")