This is an automated email from the ASF dual-hosted git repository.

bodewig pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ant.git


The following commit(s) were added to refs/heads/master by this push:
     new 4d1d05e98 use default timezone and locale in tstamp when 
SOURCE_DATE_EPOCH is used
4d1d05e98 is described below

commit 4d1d05e989c0ffa493164ff9c4f2156676d1d773
Author: Stefan Bodewig <[email protected]>
AuthorDate: Sat Apr 11 15:01:47 2026 +0200

    use default timezone and locale in tstamp when SOURCE_DATE_EPOCH is used
---
 WHATSNEW                                           | 11 ++++++
 manual/Tasks/tstamp.html                           |  8 +++++
 src/main/org/apache/tools/ant/taskdefs/Tstamp.java | 40 +++++++++++++++++++++-
 3 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/WHATSNEW b/WHATSNEW
index 8bb2127b0..c6748d23f 100644
--- a/WHATSNEW
+++ b/WHATSNEW
@@ -1,6 +1,17 @@
 Changes from Ant 1.10.17 TO Ant 1.10.18
 =======================================
 
+Other changes:
+--------------
+
+ * when using the SOURCE_DATE_EPOCH environment variable to set the
+   time for <tstamp> the timezone will now be set to UTC for DSTAMP,
+   TSTAMP and TODAY. This also applies to nested formats where and
+   locale now also defaults to en_US unless it (or the timezone) have
+   been set explicitly.
+   Based on a patch used by the Debian Ant package maintainers.
+   Part of Bugzilla Report 61269
+
 Changes from Ant 1.10.16 TO Ant 1.10.17
 =======================================
 
diff --git a/manual/Tasks/tstamp.html b/manual/Tasks/tstamp.html
index c4183da25..3b1bf8c8f 100644
--- a/manual/Tasks/tstamp.html
+++ b/manual/Tasks/tstamp.html
@@ -51,6 +51,14 @@ <h3>Description</h3>
   for that environment variable and will instead use the "current" date.
 </p>
 
+<p>
+  <em>Since Ant 1.10.18</em> if the <code>SOURCE_DATE_EPOCH</code>
+  environment variable is used by the task, the timezone of DSTAMP,
+  TSTAMP and TODAY will be set to UTC. This is also true for nested
+  format elements where in addition the locale defaults to en_US
+  unless they are specified as part of the format element explicitly.
+</p>
+
 <h3>Parameters</h3>
 <table class="attr">
   <tr>
diff --git a/src/main/org/apache/tools/ant/taskdefs/Tstamp.java 
b/src/main/org/apache/tools/ant/taskdefs/Tstamp.java
index ca10efe00..d0b27ba2a 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Tstamp.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Tstamp.java
@@ -51,6 +51,8 @@ import org.apache.tools.ant.types.EnumeratedAttribute;
 public class Tstamp extends Task {
 
     private static final String ENV_SOURCE_DATE_EPOCH = "SOURCE_DATE_EPOCH";
+    private static final TimeZone DEFAULT_TIME_ZONE = 
TimeZone.getTimeZone("UTC");
+    private static final String DEFAULT_LOCALE = "en_US";
 
     private List<CustomFormat> customFormats = new Vector<>();
     private String prefix = "";
@@ -78,29 +80,42 @@ public class Tstamp extends Task {
         try {
             Date d = getNow();
             // Honour reproducible builds 
https://reproducible-builds.org/specs/source-date-epoch/#idm55
+            boolean reproducibleBuild = false;
             final String epoch = System.getenv(ENV_SOURCE_DATE_EPOCH);
             try {
                 if (epoch != null) {
                     // Value of SOURCE_DATE_EPOCH will be an integer, 
representing seconds.
                     d = new Date(Long.parseLong(epoch) * 1000L);
                     log("Honouring environment variable " + 
ENV_SOURCE_DATE_EPOCH + " which has been set to " + epoch);
+                    reproducibleBuild = true;
                 }
             } catch(NumberFormatException e) {
                 // ignore
                 log("Ignoring invalid value '" + epoch + "' for " + 
ENV_SOURCE_DATE_EPOCH
                         + " environment variable", Project.MSG_DEBUG);
             }
+            final boolean reproducibleBuildRequested = reproducibleBuild;
             final Date date = d;
-            customFormats.forEach(cts -> cts.execute(getProject(), date, 
getLocation()));
+            customFormats
+                .forEach(cts -> cts.execute(getProject(), date, getLocation(), 
reproducibleBuildRequested));
 
             SimpleDateFormat dstamp = new SimpleDateFormat("yyyyMMdd");
+            if (reproducibleBuildRequested) {
+                dstamp.setTimeZone(DEFAULT_TIME_ZONE);
+            }
             setProperty("DSTAMP", dstamp.format(d));
 
             SimpleDateFormat tstamp = new SimpleDateFormat("HHmm");
+            if (reproducibleBuildRequested) {
+                tstamp.setTimeZone(DEFAULT_TIME_ZONE);
+            }
             setProperty("TSTAMP", tstamp.format(d));
 
             SimpleDateFormat today
                 = new SimpleDateFormat("MMMM d yyyy", Locale.US);
+            if (reproducibleBuildRequested) {
+                today.setTimeZone(DEFAULT_TIME_ZONE);
+            }
             setProperty("TODAY", today.format(d));
 
         } catch (Exception e) {
@@ -325,6 +340,29 @@ public class Tstamp extends Task {
             }
             Tstamp.this.setProperty(propertyName, sdf.format(date));
         }
+
+        /**
+         * validate parameter and execute the format.
+         * @param project project to set property in.
+         * @param date date to use as a starting point.
+         * @param location line in file (for errors)
+         * @param reproducibleBuildRequested whether reproducible
+         * builds are requestes - in which case defaults for timezone
+         * and locale may be applied
+         * @since Ant 1.10.18
+         */
+        public void execute(Project project, Date date, Location location,
+                            boolean reproducibleBuildRequested) {
+            if (reproducibleBuildRequested) {
+                if (language == null) {
+                    language = DEFAULT_LOCALE;
+                }
+                if (timeZone == null) {
+                    timeZone = DEFAULT_TIME_ZONE;
+                }
+            }
+            execute(project, date, location);
+        }
     }
 
     /**

Reply via email to