Skip to content

Pin zip entry timestamps to 1980-01-01 to match Excel#1755

Open
ken-swyfft wants to merge 1 commit intonissl-lab:masterfrom
swyfft-insurance:fix/ks/20260324_deterministic-zip-timestamps
Open

Pin zip entry timestamps to 1980-01-01 to match Excel#1755
ken-swyfft wants to merge 1 commit intonissl-lab:masterfrom
swyfft-insurance:fix/ks/20260324_deterministic-zip-timestamps

Conversation

@ken-swyfft
Copy link
Contributor

@ken-swyfft ken-swyfft commented Mar 24, 2026

Summary

This is to fix a flaky Bug56468 test that would periodically fail when doing a byte-by-byte comparison with two files saved with the exact same data. The issue is that the zip entries have timestamps, and if the test passes a two-second DOS timestamp accuracy, the two files wouldn't be exactly the same. This fixes that flaky test by:

  • Pin all zip entry timestamps to 1980-01-01 00:00:00 (the DOS epoch minimum), matching Excel's behavior
  • Adds ZipHelper.ZipEntryTimestamp constant used across all 5 ZipEntry creation sites in OPC packaging

Background

Excel sets all zip entry timestamps inside .xlsx files to 1980-01-01 00:00:00. NPOI was using DateTime.Now (SharpZipLib's default), which meant:

  1. Two writes of the same workbook could produce different bytes if they straddled a 2-second DOS time boundary
  2. Bug56468 (which asserts byte-identical output from consecutive writes) failed intermittently in CI under load
  3. NPOI output was non-deterministic — identical content produced different file hashes

This matches how other xlsx libraries handle it (e.g., XlsxWriter adopted the same fix after inspecting Excel-generated files). Apache POI added similar deterministic timestamp support in v5.4.0 via SOURCE_DATE_EPOCH.

Changed files

File Change
openxml4Net/OPC/Internal/ZipHelper.cs Added ZipEntryTimestamp constant; applied to GetCorePropertiesZipEntry
openxml4Net/OPC/Internal/Marshallers/ZipPartMarshaller.cs Applied to part entries and relationship entries
openxml4Net/OPC/Internal/ZipContentTypeManager.cs Applied to [Content_Types].xml entry
openxml4Net/OPC/Internal/Marshallers/ZipPackagePropertiesMarshaller.cs Applied to properties entry
ooxml/XSSF/Streaming/SXSSFWorkbook.cs Applied to SXSSF streaming write path

Test plan

🤖 Generated with Claude Code

Excel sets all zip entry timestamps to the DOS epoch minimum
(1980-01-01 00:00:00). NPOI was using DateTime.Now, which made output
non-deterministic and caused flaky CI failures in Bug56468 when two
consecutive writes of the same workbook straddled a 2-second DOS time
boundary.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@tonyqus
Copy link
Member

tonyqus commented Mar 25, 2026

/oc

@opencode-agent
Copy link
Contributor

Summary: PR to fix non-deterministic zip timestamps in XLSX files by pinning all ZipEntry timestamps to 1980-01-01 00:00:00 (Excel's standard). Adds a ZipHelper.ZipEntryTimestamp constant applied across 5 creation sites in OPC packaging. Fixes the flaky Bug56468 test and ensures identical workbook writes produce identical byte output. All tests pass (4545 passed, 124 skipped).

New%20session%20-%202026-03-25T06%3A11%3A11.840Z
opencode session  |  github run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants