From 50cbebcfe6f6740a5243b6079013d4203c6647f2 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Thu, 9 Apr 2026 11:11:23 +0200 Subject: [PATCH 1/5] lower pytz dependency back to 2020.1 (pandas 2.3) --- ci/deps/actions-311-minimum_versions.yaml | 2 +- ci/deps/actions-311.yaml | 2 +- ci/deps/actions-312.yaml | 2 +- ci/deps/actions-313-downstream_compat.yaml | 2 +- ci/deps/actions-313.yaml | 2 +- ci/deps/actions-314.yaml | 2 +- doc/source/getting_started/install.rst | 2 +- environment.yml | 2 +- pandas/compat/_optional.py | 2 +- pixi.toml | 2 +- pyproject.toml | 4 ++-- requirements-dev.txt | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ci/deps/actions-311-minimum_versions.yaml b/ci/deps/actions-311-minimum_versions.yaml index 8de1f729dca00..799f8e6950afa 100644 --- a/ci/deps/actions-311-minimum_versions.yaml +++ b/ci/deps/actions-311-minimum_versions.yaml @@ -50,7 +50,7 @@ dependencies: - pyreadstat=1.2.8 - pytables=3.10.1 - python-calamine=0.3.0 - - pytz=2024.2 + - pytz=2020.1 - pyxlsb=1.0.10 - s3fs=2024.10.0 - scipy=1.14.1 diff --git a/ci/deps/actions-311.yaml b/ci/deps/actions-311.yaml index ad91730734629..70b87ba685eb3 100644 --- a/ci/deps/actions-311.yaml +++ b/ci/deps/actions-311.yaml @@ -49,7 +49,7 @@ dependencies: - pyreadstat>=1.2.8 - pytables>=3.10.1 - python-calamine>=0.3.0 - - pytz>=2024.2 + - pytz>=2020.1 - pyxlsb>=1.0.10 - s3fs>=2024.10.0 - scipy>=1.14.1 diff --git a/ci/deps/actions-312.yaml b/ci/deps/actions-312.yaml index 27655942331cd..eb71afd616eea 100644 --- a/ci/deps/actions-312.yaml +++ b/ci/deps/actions-312.yaml @@ -49,7 +49,7 @@ dependencies: - pyreadstat>=1.2.8 - pytables>=3.10.1 - python-calamine>=0.3.0 - - pytz>=2024.2 + - pytz>=2020.1 - pyxlsb>=1.0.10 - s3fs>=2024.10.0 - scipy>=1.14.1 diff --git a/ci/deps/actions-313-downstream_compat.yaml b/ci/deps/actions-313-downstream_compat.yaml index 5303da5d587e2..4cab43c0197d3 100644 --- a/ci/deps/actions-313-downstream_compat.yaml +++ b/ci/deps/actions-313-downstream_compat.yaml @@ -48,7 +48,7 @@ dependencies: - pyreadstat>=1.2.8 - pytables>=3.10.1 - python-calamine>=0.3.0 - - pytz>=2024.2 + - pytz>=2020.1 - pyxlsb>=1.0.10 - s3fs>=2024.10.0 - scipy>=1.14.1 diff --git a/ci/deps/actions-313.yaml b/ci/deps/actions-313.yaml index 227f461372261..d06bc6a2a1455 100644 --- a/ci/deps/actions-313.yaml +++ b/ci/deps/actions-313.yaml @@ -50,7 +50,7 @@ dependencies: - pyreadstat>=1.2.8 - pytables>=3.10.1 - python-calamine>=0.3.0 - - pytz>=2024.2 + - pytz>=2020.1 - pyxlsb>=1.0.10 - s3fs>=2024.10.0 - scipy>=1.14.1 diff --git a/ci/deps/actions-314.yaml b/ci/deps/actions-314.yaml index 3a6189db65fb7..260fc6a217e87 100644 --- a/ci/deps/actions-314.yaml +++ b/ci/deps/actions-314.yaml @@ -48,7 +48,7 @@ dependencies: - pyreadstat>=1.2.8 - pytables>=3.10.1 - python-calamine>=0.3.0 - - pytz>=2024.2 + - pytz>=2020.1 - pyxlsb>=1.0.10 - s3fs>=2024.10.0 - scipy>=1.14.1 diff --git a/doc/source/getting_started/install.rst b/doc/source/getting_started/install.rst index c1d5184a4b3e2..e3b2a01adc115 100644 --- a/doc/source/getting_started/install.rst +++ b/doc/source/getting_started/install.rst @@ -379,5 +379,5 @@ Installable with ``pip install "pandas[timezone]"`` ========================================== ================== =================== ============================================== Dependency Minimum Version pip extra Notes ========================================== ================== =================== ============================================== -`pytz `__ 2024.2 timezone Alternative timezone library to ``zoneinfo``. +`pytz `__ 2020.1 timezone Alternative timezone library to ``zoneinfo``. ========================================== ================== =================== ============================================== diff --git a/environment.yml b/environment.yml index ac09a6945ce96..9b519c6dc170c 100644 --- a/environment.yml +++ b/environment.yml @@ -49,7 +49,7 @@ dependencies: - pyreadstat>=1.2.8 - pytables>=3.10.1 - python-calamine>=0.3.0 - - pytz>=2024.2 + - pytz>=2020.1 - pyxlsb>=1.0.10 - s3fs>=2024.10.0 - scipy>=1.14.1 diff --git a/pandas/compat/_optional.py b/pandas/compat/_optional.py index 6a6aaa04c5300..8fa5625712a18 100644 --- a/pandas/compat/_optional.py +++ b/pandas/compat/_optional.py @@ -43,7 +43,7 @@ "pyreadstat": "1.2.8", "pytest": "8.3.4", "python-calamine": "0.3.0", - "pytz": "2024.2", + "pytz": "2020.1", "pyxlsb": "1.0.10", "s3fs": "2024.10.0", "scipy": "1.14.1", diff --git a/pixi.toml b/pixi.toml index 2388af217c20d..973c7aae36802 100644 --- a/pixi.toml +++ b/pixi.toml @@ -87,7 +87,7 @@ pymysql = ">=1.1.1" pyreadstat = ">=1.2.8" pytables = ">=3.10.1" python-calamine = ">=0.3.0" -pytz = ">=2024.2" +pytz = ">=2020.1" pyxlsb = ">=1.0.10" s3fs = ">=2024.10.0" scipy = ">=1.14.1" diff --git a/pyproject.toml b/pyproject.toml index 8fd36578f8d62..73ba649e8b58f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,7 +102,7 @@ plot = ['matplotlib>=3.9.3'] output-formatting = ['jinja2>=3.1.5', 'tabulate>=0.9.0'] clipboard = ['PyQt5>=5.15.9', 'qtpy>=2.4.2'] compression = ['zstandard>=0.23.0'] -timezone = ['pytz>=2024.2'] +timezone = ['pytz>=2020.1'] all = ['adbc-driver-postgresql>=1.2.0', 'adbc-driver-sqlite>=1.2.0', 'beautifulsoup4>=4.12.3', @@ -128,7 +128,7 @@ all = ['adbc-driver-postgresql>=1.2.0', 'pytest>=8.3.4', 'pytest-xdist>=3.6.1', 'python-calamine>=0.3.0', - 'pytz>=2024.2', + 'pytz>=2020.1', 'pyxlsb>=1.0.10', 'qtpy>=2.4.2', 'scipy>=1.14.1', diff --git a/requirements-dev.txt b/requirements-dev.txt index 6210e9a365913..1baf0839000f2 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -38,7 +38,7 @@ pymysql>=1.1.1 pyreadstat>=1.2.8 tables>=3.10.1 python-calamine>=0.3.0 -pytz>=2024.2 +pytz>=2020.1 pyxlsb>=1.0.10 s3fs>=2024.10.0 scipy>=1.14.1 From dbe3e155f9841fac2ee0be0091d038f36a1d359e Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Thu, 9 Apr 2026 11:52:15 +0200 Subject: [PATCH 2/5] error on dtype creation when pytz timezone is passed and pytz is too old --- pandas/_libs/tslibs/timezones.pyx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/timezones.pyx b/pandas/_libs/tslibs/timezones.pyx index 7e245289ac9d6..d240a979e58f5 100644 --- a/pandas/_libs/tslibs/timezones.pyx +++ b/pandas/_libs/tslibs/timezones.pyx @@ -160,6 +160,9 @@ cpdef inline tzinfo maybe_get_tz(object tz): elif is_integer_object(tz): tz = timezone(timedelta(seconds=tz)) elif isinstance(tz, tzinfo): + if treat_tz_as_pytz(tz) and pytz is None: + # call again for raising proper error + import_optional_dependency("pytz") pass elif tz is None: pass @@ -435,6 +438,6 @@ def tz_standardize(tz: tzinfo) -> tzinfo: >>> tz_standardize(tz) """ - if treat_tz_as_pytz(tz): + if treat_tz_as_pytz(tz) and pytz is not None: return pytz.timezone(str(tz)) return tz From dc6176fd444c6d418cf9ad0d761b28c7da629184 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Thu, 9 Apr 2026 14:38:01 +0200 Subject: [PATCH 3/5] add whatsnew --- doc/source/whatsnew/v3.0.3.rst | 2 ++ pandas/_libs/tslibs/timezones.pyx | 6 +++--- pandas/compat/_optional.py | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/source/whatsnew/v3.0.3.rst b/doc/source/whatsnew/v3.0.3.rst index f8987257b4858..c0ab297f930ae 100644 --- a/doc/source/whatsnew/v3.0.3.rst +++ b/doc/source/whatsnew/v3.0.3.rst @@ -14,6 +14,8 @@ including other versions of pandas. Fixed regressions ~~~~~~~~~~~~~~~~~ +- Fixed reading of Parquet files with timezone-aware timestamps when an older version of pytz was installed (:issue:`64978`) + .. --------------------------------------------------------------------------- .. _whatsnew_303.bug_fixes: diff --git a/pandas/_libs/tslibs/timezones.pyx b/pandas/_libs/tslibs/timezones.pyx index d240a979e58f5..0be4a7f0b9104 100644 --- a/pandas/_libs/tslibs/timezones.pyx +++ b/pandas/_libs/tslibs/timezones.pyx @@ -160,9 +160,9 @@ cpdef inline tzinfo maybe_get_tz(object tz): elif is_integer_object(tz): tz = timezone(timedelta(seconds=tz)) elif isinstance(tz, tzinfo): - if treat_tz_as_pytz(tz) and pytz is None: - # call again for raising proper error - import_optional_dependency("pytz") + # if treat_tz_as_pytz(tz) and pytz is None: + # # call again for raising proper error + # import_optional_dependency("pytz") pass elif tz is None: pass diff --git a/pandas/compat/_optional.py b/pandas/compat/_optional.py index 8fa5625712a18..c4d00c882cb05 100644 --- a/pandas/compat/_optional.py +++ b/pandas/compat/_optional.py @@ -43,7 +43,7 @@ "pyreadstat": "1.2.8", "pytest": "8.3.4", "python-calamine": "0.3.0", - "pytz": "2020.1", + "pytz": "2020.1", # keep this pinned (https://github.com/pandas-dev/pandas/pull/65133) "pyxlsb": "1.0.10", "s3fs": "2024.10.0", "scipy": "1.14.1", From 19393f1b7912bd4a0b694e2ae469c54cd1740ca0 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Thu, 9 Apr 2026 14:39:41 +0200 Subject: [PATCH 4/5] reword --- doc/source/whatsnew/v3.0.3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v3.0.3.rst b/doc/source/whatsnew/v3.0.3.rst index c0ab297f930ae..d50d1edae98b6 100644 --- a/doc/source/whatsnew/v3.0.3.rst +++ b/doc/source/whatsnew/v3.0.3.rst @@ -14,7 +14,7 @@ including other versions of pandas. Fixed regressions ~~~~~~~~~~~~~~~~~ -- Fixed reading of Parquet files with timezone-aware timestamps when an older version of pytz was installed (:issue:`64978`) +- Fixed reading of Parquet files with timezone-aware timestamps or localizing of a timeseries with a ``pytz`` timezone when an older version of ``pytz`` was installed (:issue:`64978`) .. --------------------------------------------------------------------------- .. _whatsnew_303.bug_fixes: From b3c68f868506b7b858bd77c6112095bce744a006 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Fri, 10 Apr 2026 10:48:07 +0200 Subject: [PATCH 5/5] fixup --- pandas/_libs/tslibs/timezones.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/_libs/tslibs/timezones.pyx b/pandas/_libs/tslibs/timezones.pyx index 0be4a7f0b9104..d240a979e58f5 100644 --- a/pandas/_libs/tslibs/timezones.pyx +++ b/pandas/_libs/tslibs/timezones.pyx @@ -160,9 +160,9 @@ cpdef inline tzinfo maybe_get_tz(object tz): elif is_integer_object(tz): tz = timezone(timedelta(seconds=tz)) elif isinstance(tz, tzinfo): - # if treat_tz_as_pytz(tz) and pytz is None: - # # call again for raising proper error - # import_optional_dependency("pytz") + if treat_tz_as_pytz(tz) and pytz is None: + # call again for raising proper error + import_optional_dependency("pytz") pass elif tz is None: pass