diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index 4577d20a509ce..efb4a572486e3 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -629,6 +629,7 @@ Timedelta Timezones ^^^^^^^^^ - Bug in :meth:`Series.astype` and :meth:`DataFrame.astype` with object-dtype containing multiple timezone-aware ``datetime`` objects with heterogeneous timezones to a :class:`DatetimeTZDtype` incorrectly raising (:issue:`32581`) +- Bug in :func:`to_datetime` was failing to parse date strings with timezone name when ``format`` was specified with ``%Z`` (:issue:`49748`) - Numeric diff --git a/pandas/_libs/tslibs/parsing.pyx b/pandas/_libs/tslibs/parsing.pyx index 003ce77a221db..232169f3844b3 100644 --- a/pandas/_libs/tslibs/parsing.pyx +++ b/pandas/_libs/tslibs/parsing.pyx @@ -894,7 +894,7 @@ def format_is_iso(f: str) -> bint: for date_sep in [' ', '/', '\\', '-', '.', '']: for time_sep in [' ', 'T']: - for micro_or_tz in ['', '%z', '%Z', '.%f', '.%f%z', '.%f%Z']: + for micro_or_tz in ['', '%z', '.%f', '.%f%z']: if (iso_template(date_sep=date_sep, time_sep=time_sep, micro_or_tz=micro_or_tz, diff --git a/pandas/_libs/tslibs/src/datetime/np_datetime_strings.c b/pandas/_libs/tslibs/src/datetime/np_datetime_strings.c index 597a2aae7a2a3..7bb94012fad0c 100644 --- a/pandas/_libs/tslibs/src/datetime/np_datetime_strings.c +++ b/pandas/_libs/tslibs/src/datetime/np_datetime_strings.c @@ -539,7 +539,7 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc, /* UTC specifier */ if (*substr == 'Z') { - if (compare_format(&format, &format_len, "%Z", 2, exact)) { + if (compare_format(&format, &format_len, "%z", 2, exact)) { goto parse_error; } /* "Z" should be equivalent to tz offset "+00:00" */ diff --git a/pandas/tests/tools/test_to_datetime.py b/pandas/tests/tools/test_to_datetime.py index 22dbec337c8b1..4c70aeb3e36aa 100644 --- a/pandas/tests/tools/test_to_datetime.py +++ b/pandas/tests/tools/test_to_datetime.py @@ -1755,7 +1755,6 @@ def test_to_datetime_iso8601(self, cache, arg, exp_str): ("2012-01-01 10", "%Y-%m-%d %H:%M"), ("2012-01-01 10:00", "%Y-%m-%d %H:%M:%S"), ("2012-01-01 10:00:00", "%Y-%m-%d %H:%M:%S.%f"), - ("2012-01-01 10:00:00.123", "%Y-%m-%d %H:%M:%S.%f%Z"), ("2012-01-01 10:00:00.123", "%Y-%m-%d %H:%M:%S.%f%z"), (0, "%Y-%m-%d"), ], @@ -1861,7 +1860,7 @@ def test_to_datetime_iso8601_valid(self, input, format): [ ("2020-01-01T00:00:00.000000000+00:00", "%Y-%m-%dT%H:%M:%S.%f%z"), ("2020-01-01T00:00:00+00:00", "%Y-%m-%dT%H:%M:%S%z"), - ("2020-01-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%Z"), + ("2020-01-01T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"), ], ) def test_to_datetime_iso8601_with_timezone_valid(self, input, format): @@ -1916,6 +1915,12 @@ def test_to_datetime_with_apply(self, cache): result = td.apply(to_datetime, format="%b %y", cache=cache) tm.assert_series_equal(result, expected) + def test_to_datetime_timezone_name(self): + # https://github.com/pandas-dev/pandas/issues/49748 + result = to_datetime("2020-01-01 00:00:00UTC", format="%Y-%m-%d %H:%M:%S%Z") + expected = Timestamp(2020, 1, 1).tz_localize("UTC") + assert result == expected + @td.skip_if_not_us_locale def test_to_datetime_with_apply_with_empty_str(self, cache): # this is only locale tested with US/None locales diff --git a/pandas/tests/tslibs/test_parsing.py b/pandas/tests/tslibs/test_parsing.py index 629144341f5cb..4d7501cdadcd9 100644 --- a/pandas/tests/tslibs/test_parsing.py +++ b/pandas/tests/tslibs/test_parsing.py @@ -284,10 +284,10 @@ def test_parse_time_string_check_instance_type_raise_exception(): ("%Y%m%d %H:%M:%S", True), ("%Y-%m-%dT%H:%M:%S", True), ("%Y-%m-%dT%H:%M:%S%z", True), - ("%Y-%m-%dT%H:%M:%S%Z", True), + ("%Y-%m-%dT%H:%M:%S%Z", False), ("%Y-%m-%dT%H:%M:%S.%f", True), ("%Y-%m-%dT%H:%M:%S.%f%z", True), - ("%Y-%m-%dT%H:%M:%S.%f%Z", True), + ("%Y-%m-%dT%H:%M:%S.%f%Z", False), ("%Y%m%d", False), ("%Y%m", False), ("%Y", False),