[tools] review DateTool reenginering:
- fix stupid bug: don't ingore timezones for date only formats (silly me!)
- review standard formats:
x iso and iso_tz for ISO 8601 format (time zone displayed by offset)
x intl and intl_tz for human-readable international format (time zone displayed by id)
git-svn-id: https://svn.apache.org/repos/asf/velocity/tools/trunk@1771916 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/velocity-tools-generic/src/main/java/org/apache/velocity/tools/ConversionUtils.java b/velocity-tools-generic/src/main/java/org/apache/velocity/tools/ConversionUtils.java
index 532cf65..9ddf241 100644
--- a/velocity-tools-generic/src/main/java/org/apache/velocity/tools/ConversionUtils.java
+++ b/velocity-tools-generic/src/main/java/org/apache/velocity/tools/ConversionUtils.java
@@ -19,13 +19,17 @@
* under the License.
*/
+import org.slf4j.LoggerFactory;
+
import java.io.File;
import java.lang.reflect.Array;
import java.net.URL;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
+import java.text.FieldPosition;
import java.text.NumberFormat;
+import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
@@ -48,28 +52,16 @@
{
public static final ConversionUtils INSTANCE = new ConversionUtils();
+ /*
+ * Number formatting and parsing utilities
+ */
+
private static final int STYLE_NUMBER = 0;
private static final int STYLE_CURRENCY = 1;
private static final int STYLE_PERCENT = 2;
//NOTE: '3' belongs to a non-public "scientific" style
private static final int STYLE_INTEGER = 4;
- /* Java DateFormat standard constants extensions */
- private static final int STYLE_ISO = 5; /* ISO 8601 format */
- private static final int STYLE_ISO_TZ = 6; /* ISO 8601 format with timezone offset */
- private static final int STYLE_INTL = 7; /* ISO 8601 human-readable format */
- private static final int STYLE_INTL_TZ = 8; /* ISO 8601 human-readable format with timezone ID */
-
- /* iso/intl date/time formats (locale-independant) */
- private static DateFormat isoDateFormat = new SimpleDateFormat("yyyy-MM-dd"); /* ISO 8601 date */
- private static DateFormat isoTimeFormat = new SimpleDateFormat("HH:mm:ss"); /* ISO 8601 time */
- private static DateFormat isoTimestampFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); /* ISO 88601 timestamp */
- private static DateFormat intlTimestampFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /* human-readable ISO-8601 timestamp */
- private static DateFormat isoTimeTzFormat = new SimpleDateFormat("HH:mm:ssXXX"); /* ISO 8601 time with timezone offset */
- private static DateFormat isoTimestampTzFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); /* ISO 88601 timestamp with timezone offset */
- private static DateFormat intlTimeTzFormat = new SimpleDateFormat("HH:mm:ss zzz"); /* human-readable ISO-8601 time with timezone Olson ID */
- private static DateFormat intlTimestampTzFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz"); /* human-readable ISO-8601 timestamp with timezone Olson ID */
-
// cache custom formats
private static ConcurrentMap<String,NumberFormat> customFormatsCache = new ConcurrentHashMap<String,NumberFormat>();
@@ -312,8 +304,71 @@
return toNumber(String.valueOf(value), format, locale);
}
+ /*
+ * Date/time formatting & parsing utilities
+ */
- // -------------------------- DateFormat creation methods --------------
+ /* Java DateFormat standard constants extensions */
+ private static final int STYLE_ISO = 5; /* ISO 8601 format */
+ private static final int STYLE_ISO_TZ = 6; /* ISO 8601 format with timezone offset */
+ private static final int STYLE_INTL = 7; /* ISO 8601 human-readable format */
+ private static final int STYLE_INTL_TZ = 8; /* ISO 8601 human-readable format with timezone ID */
+
+ /* iso/intl date/time formats (locale-independant) */
+ private static DateFormat isoDateFormat = new SimpleDateFormat("yyyy-MM-dd"); /* ISO 8601 date */
+ private static DateFormat isoTimeFormat = new SimpleDateFormat("HH:mm:ss"); /* ISO 8601 time */
+ private static DateFormat isoTimestampFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); /* ISO 88601 timestamp */
+ private static DateFormat intlTimestampFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /* human-readable ISO-8601 timestamp */
+ private static DateFormat isoTimeTzFormat = new SimpleDateFormat("HH:mm:ssXXX"); /* ISO 8601 time with timezone offset */
+ private static DateFormat isoTimestampTzFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); /* ISO 88601 timestamp with timezone offset */
+ private static DateFormat intlTimeTzFormat_base = new SimpleDateFormat("HH:mm:ss"); /* human-readable ISO-8601 time with timezone ID */
+ private static DateFormat intlTimestampTzFormat_base = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /* human-readable ISO-8601 timestamp with timezone ID */
+
+ /* a DateFormat that appends a space and the time zone ID to the wrapped DateFormat - needed because
+ * there is no letter format for time zone id in SimpleDateFormat. */
+ private static class TimeZoneIDSuffixFormat extends DateFormat
+ {
+ TimeZoneIDSuffixFormat(DateFormat wrappedFormat)
+ {
+ this.wrappedFormat = wrappedFormat;
+ this.calendar = wrappedFormat.getCalendar();
+ this.numberFormat = wrappedFormat.getNumberFormat();
+ }
+
+ @Override
+ public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition)
+ {
+ StringBuffer sb = wrappedFormat.format(date, toAppendTo, fieldPosition);
+ sb.append(' ');
+ sb.append(getTimeZone().getID());
+ return sb;
+ }
+
+ /* This format is only here for formatting purposes... */
+ @Override
+ public Date parse(String source, ParsePosition pos)
+ {
+ throw new UnsupportedOperationException("intl_tz date/time formats cannot be used to parse dates");
+ }
+
+ @Override
+ public void setCalendar(Calendar newCalendar)
+ {
+ super.setCalendar(newCalendar);
+ wrappedFormat.setCalendar(newCalendar);
+ }
+
+ @Override
+ public void setNumberFormat(NumberFormat newNumberFormat)
+ {
+ super.setNumberFormat(newNumberFormat);
+ wrappedFormat.setNumberFormat(newNumberFormat);
+ }
+
+ /* no need to override setCalendar, since the calendar is shared between us and the wrapped format */
+
+ private DateFormat wrappedFormat;
+ }
/**
* Returns a {@link DateFormat} instance for the specified
@@ -414,7 +469,7 @@
if (dateStyle < 0 && timeStyle < 0)
{
// no style was specified, use default instance
- df = DateFormat.getInstance();
+ df = DateFormat.getDateInstance();
}
else if (timeStyle < 0)
{
@@ -422,14 +477,13 @@
switch (dateStyle)
{
case STYLE_ISO:
- case STYLE_ISO_TZ: /* isgnore TZ */
+ case STYLE_ISO_TZ: /* ignore TZ */
case STYLE_INTL:
case STYLE_INTL_TZ: /* ignore TZ */
- df = isoDateFormat;
+ df = (DateFormat)isoDateFormat.clone();
break;
default:
df = DateFormat.getDateInstance(dateStyle, locale);
- df.setTimeZone(timezone);
break;
}
}
@@ -440,19 +494,16 @@
{
case STYLE_ISO:
case STYLE_INTL:
- df = isoTimeFormat;
+ df = (DateFormat)isoTimeFormat.clone();
break;
case STYLE_ISO_TZ:
df = (DateFormat)isoTimeTzFormat.clone();
- df.setTimeZone(timezone);
break;
case STYLE_INTL_TZ:
- df = (DateFormat)intlTimeTzFormat.clone();
- df.setTimeZone(timezone);
+ df = new TimeZoneIDSuffixFormat((DateFormat)intlTimeTzFormat_base.clone());
break;
default:
df = DateFormat.getTimeInstance(timeStyle, locale);
- df.setTimeZone(timezone);
break;
}
}
@@ -465,25 +516,24 @@
break;
case STYLE_ISO_TZ:
df = (DateFormat)isoTimestampTzFormat.clone();
- df.setTimeZone(timezone);
break;
case STYLE_INTL:
- df = intlTimestampFormat;
+ df = (DateFormat)intlTimestampFormat.clone();
break;
case STYLE_INTL_TZ:
- df = (DateFormat) intlTimestampTzFormat.clone();
- df.setTimeZone(timezone);
+ df = new TimeZoneIDSuffixFormat((DateFormat)intlTimestampTzFormat_base.clone());
break;
default:
df = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
- df.setTimeZone(timezone);
break;
}
}
+ df.setTimeZone(timezone);
return df;
}
catch (Exception suppressed)
{
+ LoggerFactory.getLogger(ConversionUtils.class).error("could not get date/time format", suppressed);
// let it go...
return null;
}
@@ -792,5 +842,4 @@
catch (Exception e) {}
return null;
}
-
}
diff --git a/velocity-tools-generic/src/main/java/org/apache/velocity/tools/generic/DateTool.java b/velocity-tools-generic/src/main/java/org/apache/velocity/tools/generic/DateTool.java
index 0de5e6e..36d7e97 100644
--- a/velocity-tools-generic/src/main/java/org/apache/velocity/tools/generic/DateTool.java
+++ b/velocity-tools-generic/src/main/java/org/apache/velocity/tools/generic/DateTool.java
@@ -558,7 +558,7 @@
* @param locale the {@link Locale} to be used
* @param timezone the {@link TimeZone} to be used
* @return an instance of {@link DateFormat}
- * @see {@link DateFormat#getDateFormat(int timeStyle, int dateStyle, Locale locale, TimeZone timezone)}
+ * @see {@link ConversionUtils#getDateFormat(String, Locale, TimeZone)}
* @since VelocityTools 1.1
*/
public DateFormat getDateFormat(String dateStyle, String timeStyle,
diff --git a/velocity-tools-generic/src/test/java/org/apache/velocity/tools/generic/DateToolTests.java b/velocity-tools-generic/src/test/java/org/apache/velocity/tools/generic/DateToolTests.java
index c2e59c8..cc642b9 100644
--- a/velocity-tools-generic/src/test/java/org/apache/velocity/tools/generic/DateToolTests.java
+++ b/velocity-tools-generic/src/test/java/org/apache/velocity/tools/generic/DateToolTests.java
@@ -92,16 +92,16 @@
{
DateTool dt = new DateTool();
Date date = new Date();
- dt.setTimeZone(TimeZone.getTimeZone("CET"));
+ dt.setTimeZone(TimeZone.getTimeZone("Europe/Paris"));
assertEquals("DateTool incorrectly formatted iso format", new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(date), dt.format("iso", date));
assertEquals("DateTool incorrectly formatted iso format", new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(date), dt.format("iso_tz",date));
assertEquals("DateTool incorrectly formatted iso format", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date), dt.format("intl",date));
- assertEquals("DateTool incorrectly formatted iso format", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz").format(date), dt.format("intl_tz",date));
+ assertEquals("DateTool incorrectly formatted iso format", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date) + " Europe/Paris", dt.format("intl_tz",date));
assertEquals("DateTool incorrectly formatted iso format", new SimpleDateFormat("yyyy-MM-dd").format(date), dt.format("iso_date",date));
assertEquals("DateTool incorrectly formatted iso format", new SimpleDateFormat("yyyy-MM-dd").format(date), dt.format("intl_date",date));
assertEquals("DateTool incorrectly formatted iso format", new SimpleDateFormat("HH:mm:ss").format(date), dt.format("iso_time",date));
assertEquals("DateTool incorrectly formatted iso format", new SimpleDateFormat("HH:mm:ss").format(date), dt.format("intl_time",date));
assertEquals("DateTool incorrectly formatted iso format", new SimpleDateFormat("HH:mm:ssXXX").format(date), dt.format("iso_tz_time",date));
- assertEquals("DateTool incorrectly formatted iso format", new SimpleDateFormat("HH:mm:ss zzz").format(date), dt.format("intl_tz_time",date));
+ assertEquals("DateTool incorrectly formatted iso format", new SimpleDateFormat("HH:mm:ss").format(date) + " Europe/Paris", dt.format("intl_tz_time",date));
}
}