https://bz.apache.org/bugzilla/show_bug.cgi?id=59909master
| @@ -40,6 +40,15 @@ Fixed bugs: | |||
| worked on OSes where sed is GNU sed. | |||
| Bugzilla Report 59898 | |||
| * <touch>'s default pattern as well as the default patterns used by | |||
| the <date> (resource) selectors depended on the JDK being used - or | |||
| rather the locale provider being used and the default locale | |||
| provider changed with Java 9. | |||
| They are now fixed and the documentation has been updated to | |||
| reflect the real patterns used rather than a non-formal description | |||
| of the expected format. | |||
| Bugzilla Report 59909 | |||
| Other changes: | |||
| -------------- | |||
| @@ -74,8 +74,10 @@ resource collections (which also includes directories). Prior to Apache Ant | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">pattern</td> | |||
| <td valign="top">SimpleDateFormat-compatible pattern string. | |||
| Defaults to MM/DD/YYYY HH:MM AM_or_PM or MM/DD/YYYY HH:MM:SS AM_or_PM. | |||
| <td valign="top">SimpleDateFormat-compatible pattern string using | |||
| the current locale. | |||
| Defaults to "MM/dd/YYYY hh:mm a" or "MM/dd/yyyy hh:mm:ss a" | |||
| using the US locale. | |||
| <b>Since Ant 1.6.3</b></td> | |||
| <td valign="top" align="center">No</td> | |||
| </tr> | |||
| @@ -641,9 +641,10 @@ platforms. | |||
| <tr> | |||
| <td valign="top">pattern</td> | |||
| <td valign="top">SimpleDateFormat-compatible pattern | |||
| for use with the <code>datetime</code> attribute</td> | |||
| for use with the <code>datetime</code> attribute using the | |||
| current locale</td> | |||
| <td align="center" valign="top"> | |||
| No, default is "MM/DD/YYYY HH:MM AM_or_PM"</td> | |||
| No, default is "MM/dd/yyyy hh:mm a" using the US locale</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">granularity</td> | |||
| @@ -173,9 +173,9 @@ | |||
| <tr> | |||
| <td valign="top">datetime</td> | |||
| <td valign="top">Specifies the date and time to test for. | |||
| Should be in the format MM/DD/YYYY HH:MM AM_or_PM, or | |||
| an alternative pattern specified via the <i>pattern</i> | |||
| attribute. | |||
| Should be in the format "MM/dd/yyyy hh:mm a" using the US | |||
| locale, or an alternative pattern specified via | |||
| the <i>pattern</i> attribute. | |||
| </td> | |||
| <td valign="top" align="center" rowspan="2">At least one of the two.</td> | |||
| </tr> | |||
| @@ -212,7 +212,8 @@ | |||
| <tr> | |||
| <td valign="top">pattern</td> | |||
| <td valign="top">The <CODE>SimpleDateFormat</CODE>-compatible pattern | |||
| to use when interpreting the <i>datetime</i> attribute. | |||
| to use when interpreting the <i>datetime</i> attribute using | |||
| the current locale. | |||
| <i>Since Ant 1.6.2</i> | |||
| </td> | |||
| <td valign="top" align="center">No</td> | |||
| @@ -61,23 +61,29 @@ public class Touch extends Task { | |||
| public static final DateFormatFactory DEFAULT_DF_FACTORY | |||
| = new DateFormatFactory() { | |||
| /* | |||
| * The initial version used DateFormat.SHORT for the | |||
| * time format, which ignores seconds. If we want | |||
| * seconds as well, we need DateFormat.MEDIUM, which | |||
| * in turn would break all old build files. | |||
| * | |||
| * First try to parse with DateFormat.SHORT and if | |||
| * that fails with MEDIUM - throw an exception if both | |||
| * fail. | |||
| */ | |||
| private ThreadLocal<DateFormat> primary = | |||
| new ThreadLocal<DateFormat>() { | |||
| @Override | |||
| protected DateFormat initialValue() { | |||
| return new SimpleDateFormat("MM/dd/yyyy hh:mm a", | |||
| Locale.US); | |||
| } | |||
| }; | |||
| private ThreadLocal<DateFormat> fallback = | |||
| new ThreadLocal<DateFormat>() { | |||
| @Override | |||
| protected DateFormat initialValue() { | |||
| return new SimpleDateFormat("MM/dd/yyyy hh:mm:ss a", | |||
| Locale.US); | |||
| } | |||
| }; | |||
| public DateFormat getPrimaryFormat() { | |||
| return DateFormat.getDateTimeInstance(DateFormat.SHORT, | |||
| DateFormat.SHORT, Locale.US); | |||
| return primary.get(); | |||
| } | |||
| public DateFormat getFallbackFormat() { | |||
| return DateFormat.getDateTimeInstance(DateFormat.SHORT, | |||
| DateFormat.MEDIUM, Locale.US); | |||
| return fallback.get(); | |||
| } | |||
| }; | |||
| private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); | |||
| @@ -137,10 +137,10 @@ public class Date implements ResourceSelector { | |||
| throw new BuildException(MILLIS_OR_DATETIME); | |||
| } | |||
| if (millis == null) { | |||
| DateFormat df = ((pattern == null) | |||
| ? DateFormat.getDateTimeInstance( | |||
| DateFormat.SHORT, DateFormat.SHORT, Locale.US) | |||
| : new SimpleDateFormat(pattern)); | |||
| String p = pattern == null ? "MM/dd/yyyy hh:mm a" : pattern; | |||
| DateFormat df = pattern == null | |||
| ? new SimpleDateFormat(p, Locale.US) | |||
| : new SimpleDateFormat(p); | |||
| try { | |||
| long m = df.parse(dateTime).getTime(); | |||
| if (m < 0) { | |||
| @@ -151,9 +151,8 @@ public class Date implements ResourceSelector { | |||
| setMillis(m); | |||
| } catch (ParseException pe) { | |||
| throw new BuildException("Date of " + dateTime | |||
| + " Cannot be parsed correctly. It should be in" | |||
| + (pattern == null | |||
| ? " MM/DD/YYYY HH:MM AM_PM" : pattern) + " format."); | |||
| + " Cannot be parsed correctly. It should be in '" | |||
| + p + "' format."); | |||
| } | |||
| } | |||
| return when.evaluate(r.getLastModified(), millis.longValue(), granularity); | |||
| @@ -34,7 +34,7 @@ import org.apache.tools.ant.types.DataType; | |||
| public abstract class BaseSelector extends DataType implements FileSelector { | |||
| private String errmsg = null; | |||
| private Throwable cause; | |||
| /** | |||
| * Do nothing constructor. | |||
| @@ -54,6 +54,19 @@ public abstract class BaseSelector extends DataType implements FileSelector { | |||
| } | |||
| } | |||
| /** | |||
| * Allows all selectors to indicate a setup error. Note that only | |||
| * the first error message is recorded. | |||
| * | |||
| * @param msg The error message any BuildException should throw. | |||
| */ | |||
| public void setError(String msg, Throwable cause) { | |||
| if (errmsg == null) { | |||
| errmsg = msg; | |||
| this.cause = cause; | |||
| } | |||
| } | |||
| /** | |||
| * Returns any error messages that have been set. | |||
| * | |||
| @@ -87,7 +100,7 @@ public abstract class BaseSelector extends DataType implements FileSelector { | |||
| verifySettings(); | |||
| } | |||
| if (getError() != null) { | |||
| throw new BuildException(errmsg); | |||
| throw new BuildException(errmsg, cause); | |||
| } | |||
| if (!isReference()) { | |||
| dieOnCircularReference(); | |||
| @@ -209,11 +209,10 @@ public class DateSelector extends BaseExtendSelector { | |||
| setError("You must provide a datetime or the number of " | |||
| + "milliseconds."); | |||
| } else if (millis < 0 && dateTime != null) { | |||
| // check millis and only set it once. | |||
| DateFormat df = ((pattern == null) | |||
| ? DateFormat.getDateTimeInstance( | |||
| DateFormat.SHORT, DateFormat.SHORT, Locale.US) | |||
| : new SimpleDateFormat(pattern)); | |||
| String p = pattern == null ? "MM/dd/yyyy hh:mm a" : pattern; | |||
| DateFormat df = pattern == null | |||
| ? new SimpleDateFormat(p, Locale.US) | |||
| : new SimpleDateFormat(p); | |||
| try { | |||
| setMillis(df.parse(dateTime).getTime()); | |||
| @@ -224,9 +223,8 @@ public class DateSelector extends BaseExtendSelector { | |||
| } | |||
| } catch (ParseException pe) { | |||
| setError("Date of " + dateTime | |||
| + " Cannot be parsed correctly. It should be in" | |||
| + ((pattern == null) | |||
| ? " MM/DD/YYYY HH:MM AM_PM" : pattern) + " format."); | |||
| + " Cannot be parsed correctly. It should be in '" | |||
| + p + "' format.", pe); | |||
| } | |||
| } | |||
| } | |||
| @@ -73,7 +73,7 @@ public class DateSelectorTest { | |||
| } catch (BuildException be3) { | |||
| assertEquals("Date of this is not a date" | |||
| + " Cannot be parsed correctly. It should be in" | |||
| + " MM/DD/YYYY HH:MM AM_PM format.", be3.getMessage()); | |||
| + " 'MM/dd/yyyy hh:mm a' format.", be3.getMessage()); | |||
| } | |||
| s = new DateSelector(); | |||