gnodet-bot commented on PR #599: URL: https://github.com/apache/maven-jar-plugin/pull/599#issuecomment-5806162612
@desruisseaux — Good catch on the "why 2 seconds" question. The short answer is: the 2-second floor is a **JDK `jar` tool decision**, not a ZIP format requirement, but it exists for a real reason. The ZIP/MS-DOS time format (16-bit) encodes seconds as `seconds ÷ 2`, giving 2-second granularity with a minimum representable value of `1980-01-01T00:00:00Z` (all bits zero in the time word). That instant is not forbidden by the ZIP specification — it is encodable. The problem is that `1980-01-01T00:00:00Z` is used as a **sentinel value** in the ZIP extended timestamp (UT/Unix extra field): the Java `ZipEntry.javaToDosTime()` method returns the bit pattern `0x210000` (`DOSTIME_BEFORE_1980`) for any date before 1980, and the extended field uses that exact sentinel to signal "this entry has no valid DOS timestamp". When you pass `1980-01-01T00:00:00Z` verbatim, the reader sees the sentinel and interprets it as pre-1980, then falls back to the UTC extra field timestamp — which gets misread as a local time, producing `1980-01-01T08:00:00Z` instead of UTC midnight (this is the bug reported during the original OpenJDK `--date` implementation review). To avoid anyone accidentally triggering this sentinel ambiguity, the JDK `jar` tool was deliberately set to reject `T00:00:00Z` and require `T00:00:02Z` as the minimum — one even-second step past the sentinel. This is a conservative margin by the `jar` tool implementers (see [openjdk-dev discussion](https://mail.openjdk.org/pipermail/compiler-dev/2021-December/018755.html)), not a ZIP format constraint. **Implication for the Javadoc on `EPOCH_MIN`:** The current wording — *"The ZIP format stores entry timestamps in MS-DOS time format, which has 2-second granularity and whose earliest representable value maps to 1980-01-01T00:00:02Z"* — is slightly imprecise. The ZIP format's earliest representable value is actually `1980-01-01T00:00:00Z`; it is the **JDK `jar` tool** that enforces `T00:00:02Z` to avoid the sentinel. A more accurate phrasing would be: ```java /** * Minimum Unix time (seconds since epoch) accepted by the {@code jar} tool. * The ZIP format stores entry timestamps in MS-DOS time format, which has 2-second * granularity and whose earliest representable value is 1980-01-01T00:00:00Z. * However, the JDK {@code jar} tool rejects that instant because it is used as a * sentinel value in ZIP extended timestamp fields, and requires at least * 1980-01-01T00:00:02Z instead. * A JUnit test verifies that this constant equals * {@code Instant.parse("1980-01-01T00:00:02Z").getEpochSecond()}. */ ``` _This review was generated by an AI agent, Hermès on behalf of @gnodet._ <!-- reviewer: gnodet-bot --> -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
