On Fri, 19 Nov 2021 16:52:36 GMT, Andrew Leonard <aleon...@openjdk.org> wrote:
> Add a new --source-date <TIMESTAMP> (epoch milliseconds) option to jar and > jmod to allow specification of time to use for created/updated jar/jmod > entries. This then allows the ability to make the content deterministic. > > Signed-off-by: Andrew Leonard <anleo...@redhat.com> Thank you for this timely pull request, Andrew! I need this pull request and also #6395 to [enable reproducible builds in JavaFX](https://github.com/openjdk/jfx/pull/446). I drove myself crazy this weekend with time zones, and if I understand your proposed changes correctly, it looks as if you're hitting the same problems as I did: 1. The [`SOURCE_DATE_EPOCH` environment variable](https://reproducible-builds.org/specs/source-date-epoch/) is defined as the number of **seconds** since the epoch of 1970-01-01T00:00:00Z, but the new command option is defined as the number of milliseconds. That makes it difficult to set `--source-date=$SOURCE_DATE_EPOCH` on the command line. 2. Calling the method `ZipEntry.setTime(long)` will not allow for reproducible builds when the builds run in different time zones. For the second problem, run the included Java Time program as shown below: $ javac Time.java $ echo $SOURCE_DATE_EPOCH 1637085342 $ date --date="@$SOURCE_DATE_EPOCH" Tue 16 Nov 2021 09:55:42 AM PST $ java Time Build timestamp = 2021-11-16T17:55:42Z $ for f in *.zip; do zipinfo -v $f | grep -e Archive -e modified; done Archive: FailsInNome.zip file last modified on (DOS date/time): 2021 Nov 16 08:55:42 Archive: FailsInRome.zip file last modified on (DOS date/time): 2021 Nov 16 18:55:42 Archive: WorksInNome.zip file last modified on (DOS date/time): 2021 Nov 16 17:55:42 Archive: WorksInRome.zip file last modified on (DOS date/time): 2021 Nov 16 17:55:42 import java.io.FileOutputStream; import java.io.IOException; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; import java.util.TimeZone; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; public class Time { static void writeZipFile(String name, ZipEntry entry) throws IOException { var output = new ZipOutputStream(new FileOutputStream(name)); output.putNextEntry(entry); output.closeEntry(); output.close(); } public static void main(String[] args) throws IOException { var instant = Instant.now().truncatedTo(ChronoUnit.SECONDS); var sourceDateEpoch = System.getenv("SOURCE_DATE_EPOCH"); if (sourceDateEpoch != null) { long seconds = Long.parseLong(sourceDateEpoch); instant = Instant.ofEpochSecond(seconds); } System.out.println("Build timestamp = " + instant); var entry = new ZipEntry("Entry"); long newTime = 1000 * instant.getEpochSecond(); TimeZone.setDefault(TimeZone.getTimeZone("America/Nome")); entry.setTime(newTime); writeZipFile("FailsInNome.zip", entry); TimeZone.setDefault(TimeZone.getTimeZone("Europe/Rome")); entry.setTime(newTime); writeZipFile("FailsInRome.zip", entry); var dosTime = LocalDateTime.ofInstant(instant, ZoneOffset.UTC); TimeZone.setDefault(TimeZone.getTimeZone("America/Nome")); entry.setTimeLocal(dosTime); writeZipFile("WorksInNome.zip", entry); TimeZone.setDefault(TimeZone.getTimeZone("Europe/Rome")); entry.setTimeLocal(dosTime); writeZipFile("WorksInRome.zip", entry); } } ------------- PR: https://git.openjdk.java.net/jdk/pull/6481