https://github.com/python/cpython/commit/9dcf94e906906ff39c7955227c2b044b515ee162
commit: 9dcf94e906906ff39c7955227c2b044b515ee162
branch: main
author: Caleb <[email protected]>
committer: jaraco <[email protected]>
date: 2026-05-20T01:36:19Z
summary:

gh-134261: ZipFile - Don't rely on local time for reproducible builds & tests 
(#134264)

---------

Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Co-authored-by: Emma Smith <[email protected]>
Co-authored-by: Jason R. Coombs <[email protected]>

files:
A Misc/NEWS.d/next/Library/2025-05-19-21-08-25.gh-issue-134261.ravGYm.rst
M Lib/test/test_zipfile/test_core.py
M Lib/zipfile/__init__.py

diff --git a/Lib/test/test_zipfile/test_core.py 
b/Lib/test/test_zipfile/test_core.py
index 0d407371f40a0f..30550263ad50aa 100644
--- a/Lib/test/test_zipfile/test_core.py
+++ b/Lib/test/test_zipfile/test_core.py
@@ -1886,11 +1886,8 @@ def test_write_with_source_date_epoch(self):
 
             with zipfile.ZipFile(TESTFN, "r") as zf:
                 zip_info = zf.getinfo("test_source_date_epoch.txt")
-                get_time = 
time.localtime(int(os.environ['SOURCE_DATE_EPOCH']))[:6]
-                # Compare each element of the date_time tuple
-                # Allow for a 1-second difference
-                for z_time, g_time in zip(zip_info.date_time, get_time):
-                    self.assertAlmostEqual(z_time, g_time, delta=1)
+                expected_utc = (2025, 1, 1, 7, 19, 58)
+                self.assertEqual(zip_info.date_time, expected_utc)
 
     def test_write_without_source_date_epoch(self):
         with os_helper.EnvironmentVarGuard() as env:
@@ -1901,9 +1898,13 @@ 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")
-                current_time = time.localtime()[:6]
-                for z_time, c_time in zip(zip_info.date_time, current_time):
-                    self.assertAlmostEqual(z_time, c_time, delta=2)
+                self.assertTimestampAlmostEqual(time.localtime(), 
zip_info.date_time, tolerance=2)
+
+    def assertTimestampAlmostEqual(self, time1, time2, tolerance):
+        import datetime
+        dt1 = datetime.datetime(*time1[:6])
+        dt2 = datetime.datetime(*time2[:6])
+        self.assertLessEqual((dt1 - dt2).total_seconds(), tolerance)
 
     def test_close(self):
         """Check that the zipfile is closed after the 'with' block."""
diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py
index 86c3bc36b695c7..c5c6ac03fb7b8c 100644
--- a/Lib/zipfile/__init__.py
+++ b/Lib/zipfile/__init__.py
@@ -663,9 +663,12 @@ def _for_archive(self, archive):
         Return self.
         """
         # gh-91279: Set the SOURCE_DATE_EPOCH to a specific timestamp
-        epoch = os.environ.get('SOURCE_DATE_EPOCH')
-        get_time = int(epoch) if epoch else time.time()
-        self.date_time = time.localtime(get_time)[:6]
+        source_date_epoch = os.environ.get('SOURCE_DATE_EPOCH')
+
+        if source_date_epoch:
+            self.date_time = time.gmtime(int(source_date_epoch))[:6]
+        else:
+            self.date_time = time.localtime(time.time())[:6]
 
         self.compress_type = archive.compression
         self.compress_level = archive.compresslevel
diff --git 
a/Misc/NEWS.d/next/Library/2025-05-19-21-08-25.gh-issue-134261.ravGYm.rst 
b/Misc/NEWS.d/next/Library/2025-05-19-21-08-25.gh-issue-134261.ravGYm.rst
new file mode 100644
index 00000000000000..bf552fee814acb
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-05-19-21-08-25.gh-issue-134261.ravGYm.rst
@@ -0,0 +1 @@
+zip: On reproducible builds, ZipFile uses UTC instead of the local time when 
writing file datetimes to avoid underflows.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to