Author: cbrisson Date: Tue Nov 29 15:21:21 2016 New Revision: 1771916 URL: http://svn.apache.org/viewvc?rev=1771916&view=rev Log: [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)
Modified: velocity/tools/trunk/velocity-tools-generic/src/main/java/org/apache/velocity/tools/ConversionUtils.java velocity/tools/trunk/velocity-tools-generic/src/main/java/org/apache/velocity/tools/generic/DateTool.java velocity/tools/trunk/velocity-tools-generic/src/test/java/org/apache/velocity/tools/generic/DateToolTests.java Modified: velocity/tools/trunk/velocity-tools-generic/src/main/java/org/apache/velocity/tools/ConversionUtils.java URL: http://svn.apache.org/viewvc/velocity/tools/trunk/velocity-tools-generic/src/main/java/org/apache/velocity/tools/ConversionUtils.java?rev=1771916&r1=1771915&r2=1771916&view=diff ============================================================================== --- velocity/tools/trunk/velocity-tools-generic/src/main/java/org/apache/velocity/tools/ConversionUtils.java (original) +++ velocity/tools/trunk/velocity-tools-generic/src/main/java/org/apache/velocity/tools/ConversionUtils.java Tue Nov 29 15:21:21 2016 @@ -19,13 +19,17 @@ package org.apache.velocity.tools; * 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 class ConversionUtils { 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 @@ public class ConversionUtils 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 @@ public class ConversionUtils 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 @@ public class ConversionUtils 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 @@ public class ConversionUtils { 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 @@ public class ConversionUtils 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 @@ public class ConversionUtils catch (Exception e) {} return null; } - } Modified: velocity/tools/trunk/velocity-tools-generic/src/main/java/org/apache/velocity/tools/generic/DateTool.java URL: http://svn.apache.org/viewvc/velocity/tools/trunk/velocity-tools-generic/src/main/java/org/apache/velocity/tools/generic/DateTool.java?rev=1771916&r1=1771915&r2=1771916&view=diff ============================================================================== --- velocity/tools/trunk/velocity-tools-generic/src/main/java/org/apache/velocity/tools/generic/DateTool.java (original) +++ velocity/tools/trunk/velocity-tools-generic/src/main/java/org/apache/velocity/tools/generic/DateTool.java Tue Nov 29 15:21:21 2016 @@ -558,7 +558,7 @@ public class DateTool extends FormatConf * @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, Modified: velocity/tools/trunk/velocity-tools-generic/src/test/java/org/apache/velocity/tools/generic/DateToolTests.java URL: http://svn.apache.org/viewvc/velocity/tools/trunk/velocity-tools-generic/src/test/java/org/apache/velocity/tools/generic/DateToolTests.java?rev=1771916&r1=1771915&r2=1771916&view=diff ============================================================================== --- velocity/tools/trunk/velocity-tools-generic/src/test/java/org/apache/velocity/tools/generic/DateToolTests.java (original) +++ velocity/tools/trunk/velocity-tools-generic/src/test/java/org/apache/velocity/tools/generic/DateToolTests.java Tue Nov 29 15:21:21 2016 @@ -92,16 +92,16 @@ public class DateToolTests { 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)); } }