From bb0a1d12c7ca70b1c76e64858bc61865e498daf9 Mon Sep 17 00:00:00 2001 From: Lohitha0-0 Date: Sun, 28 Jun 2026 00:06:36 +0530 Subject: [PATCH 1/2] gh-152445: fix zipfile.writestr() ignoring strict_timestamps when SOURCE_DATE_EPOCH is set --- Lib/test/test_zipfile/test_core.py | 31 ++++++++++++++++++++++++++++++ Lib/zipfile/__init__.py | 8 ++++++++ 2 files changed, 39 insertions(+) diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py index 4f20209927e7b3d..f6014951a1ce013 100644 --- a/Lib/test/test_zipfile/test_core.py +++ b/Lib/test/test_zipfile/test_core.py @@ -4019,6 +4019,37 @@ def test_write_without_source_date_epoch(self): with zipfile.ZipFile(TESTFN, "r") as zf: zip_info = zf.getinfo("test_no_source_date_epoch.txt") self.assertTimestampAlmostEqual(time.localtime(), zip_info.date_time, tolerance=2) + + def test_writestr_strict_timestamps_false_with_pre1980_source_date_epoch(self): + # gh-152445: writestr() with strict_timestamps=False should clamp + # SOURCE_DATE_EPOCH before 1980 to 1980-01-01, not raise. + with os_helper.EnvironmentVarGuard() as env: + env['SOURCE_DATE_EPOCH'] = '0' # 1970-01-01 + with zipfile.ZipFile(TESTFN, 'w', strict_timestamps=False) as zf: + zf.writestr('test.txt', 'Hello World') + with zipfile.ZipFile(TESTFN, 'r') as zf: + info = zf.getinfo('test.txt') + self.assertEqual(info.date_time[:3], (1980, 1, 1)) + + def test_writestr_strict_timestamps_false_with_post2107_source_date_epoch(self): + # gh-152445: writestr() with strict_timestamps=False should clamp + # SOURCE_DATE_EPOCH after 2107 to 2107-12-31, not raise. + with os_helper.EnvironmentVarGuard() as env: + env['SOURCE_DATE_EPOCH'] = '4354819200' # 2108-01-01 + with zipfile.ZipFile(TESTFN, 'w', strict_timestamps=False) as zf: + zf.writestr('test.txt', 'Hello World') + with zipfile.ZipFile(TESTFN, 'r') as zf: + info = zf.getinfo('test.txt') + self.assertEqual(info.date_time[:3], (2107, 12, 31)) + + def test_writestr_strict_timestamps_true_raises_for_pre1980_source_date_epoch(self): + # gh-152445: writestr() with strict_timestamps=True (default) should + # still raise when SOURCE_DATE_EPOCH is before 1980. + with os_helper.EnvironmentVarGuard() as env: + env['SOURCE_DATE_EPOCH'] = '0' # 1970-01-01 + with zipfile.ZipFile(TESTFN, 'w') as zf: + with self.assertRaises((struct.error, ValueError)): + zf.writestr('test.txt', 'Hello World') def assertTimestampAlmostEqual(self, time1, time2, tolerance): import datetime diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index 418933a2e8d9e87..6b2cd84887ef444 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -683,6 +683,14 @@ def _for_archive(self, archive): else: self.date_time = time.localtime(time.time())[:6] + # gh-152445: Clamp date_time when strict_timestamps=False, + # mirroring the behaviour of ZipInfo.from_file(). + if not archive._strict_timestamps: + if self.date_time[0] < 1980: + self.date_time = (1980, 1, 1, 0, 0, 0) + elif self.date_time[0] > 2107: + self.date_time = (2107, 12, 31, 23, 59, 59) + self.compress_type = archive.compression self.compress_level = archive.compresslevel if self.filename.endswith('/'): # pragma: no cover From 974fa2b1d7633b96952400a37dfac62150ebf6ca Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 27 Jun 2026 18:52:38 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Lib/test/test_zipfile/test_core.py | 2 +- .../next/Library/2026-06-27-18-52-36.gh-issue-152445.jn6xhX.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-27-18-52-36.gh-issue-152445.jn6xhX.rst diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py index f6014951a1ce013..ed73d8f0946b577 100644 --- a/Lib/test/test_zipfile/test_core.py +++ b/Lib/test/test_zipfile/test_core.py @@ -4019,7 +4019,7 @@ def test_write_without_source_date_epoch(self): with zipfile.ZipFile(TESTFN, "r") as zf: zip_info = zf.getinfo("test_no_source_date_epoch.txt") self.assertTimestampAlmostEqual(time.localtime(), zip_info.date_time, tolerance=2) - + def test_writestr_strict_timestamps_false_with_pre1980_source_date_epoch(self): # gh-152445: writestr() with strict_timestamps=False should clamp # SOURCE_DATE_EPOCH before 1980 to 1980-01-01, not raise. diff --git a/Misc/NEWS.d/next/Library/2026-06-27-18-52-36.gh-issue-152445.jn6xhX.rst b/Misc/NEWS.d/next/Library/2026-06-27-18-52-36.gh-issue-152445.jn6xhX.rst new file mode 100644 index 000000000000000..8c6d3b36737ca4d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-27-18-52-36.gh-issue-152445.jn6xhX.rst @@ -0,0 +1 @@ +Fix :func:`zipfile.ZipFile.writestr` ignoring ``strict_timestamps=False`` when ``SOURCE_DATE_EPOCH`` is set to a date before 1980 or after 2107.