LANG-1154

FastDateFormat APIs that use a StringBuilder
This commit is contained in:
Chas Honton 2015-07-13 21:46:14 -07:00
parent 03fe88ab71
commit 61579335bc
7 changed files with 330 additions and 88 deletions

View File

@ -22,6 +22,7 @@
<body>
<release version="3.5" date="tba" description="tba">
<action issue="LANG-1154" type="add" dev="chas" due-to="Gary Gregory">FastDateFormat APIs that use a StringBuilder</action>
<action issue="LANG-1149" type="add" dev="chas" due-to="Gregory Zak">Ability to throw checked exceptions without declaring them</action>
<action issue="LANG-1002" type="fix" dev="chas" due-to="Michael Osipov">Several predefined ISO FastDateFormats in DateFormatUtils are incorrect</action>
<action issue="LANG-1152" type="fix" dev="chas" due-to="Pas Filip">StringIndexOutOfBoundsException or field over-write for large year fields in FastDateParser</action>

View File

@ -59,23 +59,27 @@ public interface DatePrinter {
String format(Calendar calendar);
/**
* <p>Formats a milliseond {@code long} value into the
* <p>Formats a millisecond {@code long} value into the
* supplied {@code StringBuffer}.</p>
* @deprecated Use {{@link #format(long, Appendable)}.
*
* @param millis the millisecond value to format
* @param buf the buffer to format into
* @return the specified string buffer
*/
@Deprecated
StringBuffer format(long millis, StringBuffer buf);
/**
* <p>Formats a {@code Date} object into the
* supplied {@code StringBuffer} using a {@code GregorianCalendar}.</p>
* @deprecated Use {{@link #format(Date, Appendable)}.
*
* @param date the date to format
* @param buf the buffer to format into
* @return the specified string buffer
*/
@Deprecated
StringBuffer format(Date date, StringBuffer buf);
/**
@ -83,13 +87,51 @@ public interface DatePrinter {
* The TimeZone set on the Calendar is only used to adjust the time offset.
* The TimeZone specified during the construction of the Parser will determine the TimeZone
* used in the formatted string.
* @deprecated Use {{@link #format(Calendar, Appendable)}.
*
* @param calendar the calendar to format
* @param buf the buffer to format into
* @return the specified string buffer
*/
@Deprecated
StringBuffer format(Calendar calendar, StringBuffer buf);
/**
* <p>Formats a millisecond {@code long} value into the
* supplied {@code Appendable}.</p>
*
* @param millis the millisecond value to format
* @param buf the buffer to format into
* @return the specified string buffer
* @since 3.5
*/
<B extends Appendable> B format(long millis, B buf);
/**
* <p>Formats a {@code Date} object into the
* supplied {@code Appendable} using a {@code GregorianCalendar}.</p>
*
* @param date the date to format
* @param buf the buffer to format into
* @return the specified string buffer
* @since 3.5
*/
<B extends Appendable> B format(Date date, B buf);
/**
* <p>Formats a {@code Calendar} object into the supplied {@code Appendable}.</p>
* The TimeZone set on the Calendar is only used to adjust the time offset.
* The TimeZone specified during the construction of the Parser will determine the TimeZone
* used in the formatted string.
*
* @param calendar the calendar to format
* @param buf the buffer to format into
* @return the specified string buffer
* @since 3.5
*/
<B extends Appendable> B format(Calendar calendar, B buf);
// Accessors
//-----------------------------------------------------------------------
/**

View File

@ -399,6 +399,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
/**
* <p>Formats a {@code Date}, {@code Calendar} or
* {@code Long} (milliseconds) object.</p>
* This method is an implementation of {@link Format#format(Object, StringBuffer, FieldPosition)}
*
* @param obj the object to format
* @param toAppendTo the buffer to append to
@ -407,7 +408,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
*/
@Override
public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
return printer.format(obj, toAppendTo, pos);
return toAppendTo.append(printer.format(obj));
}
/**
@ -447,17 +448,63 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
/**
* <p>Formats a millisecond {@code long} value into the
* supplied {@code StringBuffer}.</p>
* @deprecated Use {{@link #format(long, Appendable)}.
*
* @param millis the millisecond value to format
* @param buf the buffer to format into
* @return the specified string buffer
* @since 2.1
*/
@Deprecated
@Override
public StringBuffer format(final long millis, final StringBuffer buf) {
return printer.format(millis, buf);
}
/**
* <p>Formats a {@code Date} object into the
* supplied {@code StringBuffer} using a {@code GregorianCalendar}.</p>
* @deprecated Use {{@link #format(Date, Appendable)}.
*
* @param date the date to format
* @param buf the buffer to format into
* @return the specified string buffer
*/
@Deprecated
@Override
public StringBuffer format(final Date date, final StringBuffer buf) {
return printer.format(date, buf);
}
/**
* <p>Formats a {@code Calendar} object into the
* supplied {@code StringBuffer}.</p>
* @deprecated Use {{@link #format(Calendar, Appendable)}.
*
* @param calendar the calendar to format
* @param buf the buffer to format into
* @return the specified string buffer
*/
@Deprecated
@Override
public StringBuffer format(final Calendar calendar, final StringBuffer buf) {
return printer.format(calendar, buf);
}
/**
* <p>Formats a millisecond {@code long} value into the
* supplied {@code StringBuffer}.</p>
*
* @param millis the millisecond value to format
* @param buf the buffer to format into
* @return the specified string buffer
* @since 3.5
*/
@Override
public <B extends Appendable> B format(final long millis, final B buf) {
return printer.format(millis, buf);
}
/**
* <p>Formats a {@code Date} object into the
* supplied {@code StringBuffer} using a {@code GregorianCalendar}.</p>
@ -465,9 +512,10 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @param date the date to format
* @param buf the buffer to format into
* @return the specified string buffer
* @since 3.5
*/
@Override
public StringBuffer format(final Date date, final StringBuffer buf) {
public <B extends Appendable> B format(final Date date, final B buf) {
return printer.format(date, buf);
}
@ -478,9 +526,10 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
* @param calendar the calendar to format
* @param buf the buffer to format into
* @return the specified string buffer
*/
* @since 3.5
*/
@Override
public StringBuffer format(final Calendar calendar, final StringBuffer buf) {
public <B extends Appendable> B format(final Calendar calendar, final B buf) {
return printer.format(calendar, buf);
}
@ -597,18 +646,17 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
return "FastDateFormat[" + printer.getPattern() + "," + printer.getLocale() + "," + printer.getTimeZone().getID() + "]";
}
/**
* <p>Performs the formatting by applying the rules to the
* specified calendar.</p>
* @deprecated Use {{@link #format(Calendar, Appendable)
*
* @param calendar the calendar to format
* @param buf the buffer to format into
* @return the specified string buffer
*/
@Deprecated
protected StringBuffer applyRules(final Calendar calendar, final StringBuffer buf) {
return printer.applyRules(calendar, buf);
}
}

View File

@ -32,6 +32,8 @@ import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.commons.lang3.exception.ExceptionUtils;
/**
* <p>FastDatePrinter is a fast and thread-safe version of
* {@link java.text.SimpleDateFormat}.</p>
@ -387,12 +389,13 @@ public class FastDatePrinter implements DatePrinter, Serializable {
/**
* <p>Formats a {@code Date}, {@code Calendar} or
* {@code Long} (milliseconds) object.</p>
*
* @deprecated Use {{@link #format(Date)}, {{@link #format(Calendar)}, {{@link #format(long)}, or {{@link #format(Object)}
* @param obj the object to format
* @param toAppendTo the buffer to append to
* @param pos the position - ignored
* @return the buffer passed in
*/
@Deprecated
@Override
public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
if (obj instanceof Date) {
@ -407,6 +410,26 @@ public class FastDatePrinter implements DatePrinter, Serializable {
}
}
/**
* <p>Formats a {@code Date}, {@code Calendar} or
* {@code Long} (milliseconds) object.</p>
* @since 3.5
* @param obj the object to format
* @return The formatted value.
*/
String format(Object obj) {
if (obj instanceof Date) {
return format((Date) obj);
} else if (obj instanceof Calendar) {
return format((Calendar) obj);
} else if (obj instanceof Long) {
return format(((Long) obj).longValue());
} else {
throw new IllegalArgumentException("Unknown class: " +
(obj == null ? "<null>" : obj.getClass().getName()));
}
}
/* (non-Javadoc)
* @see org.apache.commons.lang3.time.DatePrinter#format(long)
*/
@ -423,7 +446,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* @return a String representation of the given Calendar.
*/
private String applyRulesToString(final Calendar c) {
return applyRules(c, new StringBuffer(mMaxLengthEstimate)).toString();
return applyRules(c, new StringBuilder(mMaxLengthEstimate)).toString();
}
/**
@ -450,7 +473,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
*/
@Override
public String format(final Calendar calendar) {
return format(calendar, new StringBuffer(mMaxLengthEstimate)).toString();
return format(calendar, new StringBuilder(mMaxLengthEstimate)).toString();
}
/* (non-Javadoc)
@ -480,6 +503,33 @@ public class FastDatePrinter implements DatePrinter, Serializable {
return format(calendar.getTime(), buf);
}
/* (non-Javadoc)
* @see org.apache.commons.lang3.time.DatePrinter#format(long, java.lang.Appendable)
*/
@Override
public <B extends Appendable> B format(final long millis, final B buf) {
return format(new Date(millis), buf);
}
/* (non-Javadoc)
* @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Date, java.lang.Appendable)
*/
@Override
public <B extends Appendable> B format(final Date date, final B buf) {
final Calendar c = newCalendar(); // hard code GregorianCalendar
c.setTime(date);
return applyRules(c, buf);
}
/* (non-Javadoc)
* @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Calendar, java.lang.Appendable)
*/
@Override
public <B extends Appendable> B format(final Calendar calendar, final B buf) {
// do not pass in calendar directly, this will cause TimeZone of FastDatePrinter to be ignored
return format(calendar.getTime(), buf);
}
/**
* <p>Performs the formatting by applying the rules to the
* specified calendar.</p>
@ -488,9 +538,13 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* @param buf the buffer to format into
* @return the specified string buffer
*/
protected StringBuffer applyRules(final Calendar calendar, final StringBuffer buf) {
for (final Rule rule : mRules) {
rule.appendTo(buf, calendar);
protected <B extends Appendable> B applyRules(final Calendar calendar, final B buf) {
try {
for (final Rule rule : mRules) {
rule.appendTo(buf, calendar);
}
} catch (IOException ioe) {
ExceptionUtils.rethrow(ioe);
}
return buf;
}
@ -589,16 +643,45 @@ public class FastDatePrinter implements DatePrinter, Serializable {
}
/**
* Appends digits to the given buffer.
*
* Appends two digits to the given buffer.
*
* @param buffer the buffer to append to.
* @param value the value to append digits from.
*/
private static void appendDigits(final StringBuffer buffer, final int value) {
private static void appendDigits(final Appendable buffer, final int value) throws IOException {
buffer.append((char)(value / 10 + '0'));
buffer.append((char)(value % 10 + '0'));
}
private static final int MAX_DIGITS = 10; // log10(Integer.MAX_VALUE) ~= 9.3
/**
* Appends all digits to the given buffer.
*
* @param buffer the buffer to append to.
* @param value the value to append digits from.
*/
private static void appendFullDigits(final Appendable buffer, int value, int minFieldWidth) throws IOException {
// build up decimal representation in reverse
char[] work = new char[MAX_DIGITS];
int digit = 0;
while(value!=0) {
work[digit++] = (char)(value % 10 + '0');
value = value / 10;
}
// pad with zeros
while(digit<minFieldWidth) {
buffer.append('0');
--minFieldWidth;
}
// reverse
while(--digit>=0) {
buffer.append(work[digit]);
}
}
// Rules
//-----------------------------------------------------------------------
/**
@ -615,10 +698,10 @@ public class FastDatePrinter implements DatePrinter, Serializable {
/**
* Appends the value of the specified calendar to the output buffer based on the rule implementation.
*
* @param buffer the output buffer
* @param buf the output buffer
* @param calendar calendar to be appended
*/
void appendTo(StringBuffer buffer, Calendar calendar);
void appendTo(Appendable buf, Calendar calendar) throws IOException;
}
/**
@ -631,7 +714,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* @param buffer the output buffer
* @param value the value to be appended
*/
void appendTo(StringBuffer buffer, int value);
void appendTo(Appendable buffer, int value) throws IOException;
}
/**
@ -662,7 +745,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
buffer.append(mValue);
}
}
@ -695,7 +778,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
buffer.append(mValue);
}
}
@ -738,7 +821,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
buffer.append(mValues[calendar.get(mField)]);
}
}
@ -770,7 +853,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
appendTo(buffer, calendar.get(mField));
}
@ -778,13 +861,13 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public final void appendTo(final StringBuffer buffer, final int value) {
public final void appendTo(final Appendable buffer, final int value) throws IOException {
if (value < 10) {
buffer.append((char)(value + '0'));
} else if (value < 100) {
appendDigits(buffer, value);
} else {
buffer.append(value);
appendFullDigits(buffer, value, 1);
}
}
}
@ -815,7 +898,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
appendTo(buffer, calendar.get(Calendar.MONTH) + 1);
}
@ -823,7 +906,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public final void appendTo(final StringBuffer buffer, final int value) {
public final void appendTo(final Appendable buffer, final int value) throws IOException {
if (value < 10) {
buffer.append((char)(value + '0'));
} else {
@ -866,7 +949,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
appendTo(buffer, calendar.get(mField));
}
@ -874,23 +957,8 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public final void appendTo(final StringBuffer buffer, int value) {
int first = buffer.length();
// pad the buffer with adequate zeros
for(int digit = 0; digit<mSize; ++digit) {
buffer.append('0');
}
// backfill the buffer with non-zero digits
int index = buffer.length();
for( ; value>0; value /= 10) {
char c= (char)('0' + value % 10);
if(--index<first) {
buffer.insert(first, c);
}
else {
buffer.setCharAt(index, c);
}
}
public final void appendTo(final Appendable buffer, int value) throws IOException {
appendFullDigits(buffer, value, mSize);
}
}
@ -921,7 +989,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
appendTo(buffer, calendar.get(mField));
}
@ -929,11 +997,11 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public final void appendTo(final StringBuffer buffer, final int value) {
public final void appendTo(final Appendable buffer, final int value) throws IOException {
if (value < 100) {
appendDigits(buffer, value);
} else {
buffer.append(value);
appendFullDigits(buffer, value, 2);
}
}
}
@ -963,7 +1031,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
appendTo(buffer, calendar.get(Calendar.YEAR) % 100);
}
@ -971,7 +1039,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public final void appendTo(final StringBuffer buffer, final int value) {
public final void appendTo(final Appendable buffer, final int value) throws IOException {
appendDigits(buffer, value);
}
}
@ -1001,7 +1069,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
appendTo(buffer, calendar.get(Calendar.MONTH) + 1);
}
@ -1009,7 +1077,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public final void appendTo(final StringBuffer buffer, final int value) {
public final void appendTo(final Appendable buffer, final int value) throws IOException {
appendDigits(buffer, value);
}
}
@ -1042,7 +1110,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
int value = calendar.get(Calendar.HOUR);
if (value == 0) {
value = calendar.getLeastMaximum(Calendar.HOUR) + 1;
@ -1054,7 +1122,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final int value) {
public void appendTo(final Appendable buffer, final int value) throws IOException {
mRule.appendTo(buffer, value);
}
}
@ -1087,7 +1155,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
int value = calendar.get(Calendar.HOUR_OF_DAY);
if (value == 0) {
value = calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1;
@ -1099,7 +1167,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final int value) {
public void appendTo(final Appendable buffer, final int value) throws IOException {
mRule.appendTo(buffer, value);
}
}
@ -1170,7 +1238,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
final TimeZone zone = calendar.getTimeZone();
if (calendar.get(Calendar.DST_OFFSET) != 0) {
buffer.append(getTimeZoneDisplay(zone, true, mStyle, mLocale));
@ -1211,7 +1279,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
@ -1290,7 +1358,7 @@ public class FastDatePrinter implements DatePrinter, Serializable {
* {@inheritDoc}
*/
@Override
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
if (offset == 0) {
buffer.append("Z");

View File

@ -23,8 +23,9 @@ import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
@ -33,7 +34,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongArray;
import org.apache.commons.lang3.test.SystemDefaults;
import org.apache.commons.lang3.test.SystemDefaultsSwitch;
@ -232,33 +233,43 @@ public class FastDateFormatTest {
@Test
public void testParseSync() throws InterruptedException {
final String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS";
final FastDateFormat formatter= FastDateFormat.getInstance(pattern);
final long sdfTime= measureTime(formatter, new SimpleDateFormat(pattern) {
private static final long serialVersionUID = 1L; // because SimpleDateFormat is serializable
final SimpleDateFormat inner = new SimpleDateFormat(pattern);
final Format sdf= new Format() {
private static final long serialVersionUID = 1L;
@Override
public Object parseObject(final String formattedDate) throws ParseException {
synchronized(this) {
return super.parse(formattedDate);
}
}
});
final long fdfTime= measureTime(formatter, FastDateFormat.getInstance(pattern));
final String times= ">>FastDateFormatTest: FastDateParser:"+fdfTime+" SimpleDateFormat:"+sdfTime;
System.out.println(times);
@Override
public StringBuffer format(Object obj,
StringBuffer toAppendTo,
FieldPosition fieldPosition) {
synchronized(this) {
return inner.format(obj, toAppendTo, fieldPosition);
}
}
@Override
public Object parseObject(String source, ParsePosition pos) {
synchronized(this) {
return inner.parseObject(source, pos);
}
}
};
final AtomicLongArray sdfTime= measureTime(sdf, sdf);
Format fdf = FastDateFormat.getInstance(pattern);
final AtomicLongArray fdfTime= measureTime(fdf, fdf);
System.out.println(">>FastDateFormatTest: FastDatePrinter:"+fdfTime.get(0)+" SimpleDateFormat:"+sdfTime.get(0));
System.out.println(">>FastDateFormatTest: FastDateParser:"+fdfTime.get(1)+" SimpleDateFormat:"+sdfTime.get(1));
}
final static private int NTHREADS= 10;
final static private int NROUNDS= 10000;
private long measureTime(final Format formatter, final Format parser) throws InterruptedException {
private AtomicLongArray measureTime(final Format printer, final Format parser) throws InterruptedException {
final ExecutorService pool = Executors.newFixedThreadPool(NTHREADS);
final AtomicInteger failures= new AtomicInteger(0);
final AtomicLong totalElapsed= new AtomicLong(0);
final AtomicLongArray totalElapsed= new AtomicLongArray(2);
for(int i= 0; i<NTHREADS; ++i) {
pool.submit(new Runnable() {
@Override
@ -266,10 +277,15 @@ public class FastDateFormatTest {
for(int j= 0; j<NROUNDS; ++j) {
try {
final Date date= new Date();
final String formattedDate= formatter.format(date);
final long start= System.currentTimeMillis();
final long t0= System.currentTimeMillis();
final String formattedDate= printer.format(date);
totalElapsed.addAndGet(0, System.currentTimeMillis() - t0);
final long t1 = System.currentTimeMillis();
final Object pd= parser.parseObject(formattedDate);
totalElapsed.addAndGet(System.currentTimeMillis()-start);
totalElapsed.addAndGet(1, System.currentTimeMillis() - t1);
if(!date.equals(pd)) {
failures.incrementAndGet();
}
@ -290,9 +306,9 @@ public class FastDateFormatTest {
fail("did not complete tasks");
}
assertEquals(0, failures.get());
return totalElapsed.get();
return totalElapsed;
}
@Test
public void testLANG_1152() {
TimeZone utc = TimeZone.getTimeZone("UTC");

View File

@ -22,6 +22,7 @@ import static org.junit.Assert.assertTrue;
import java.io.Serializable;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
@ -666,7 +667,7 @@ public class FastDateParserTest {
@Test
public void testLang1121() throws ParseException {
TimeZone kst = TimeZone.getTimeZone("KST");
final DateParser fdp = FastDateFormat.getInstance("yyyyMMdd", kst, Locale.KOREA);
final DateParser fdp = getInstance("yyyyMMdd", kst, Locale.KOREA);
try {
fdp.parse("2015");
@ -690,4 +691,15 @@ public class FastDateParserTest {
actual = fdp.parse("20150429113100");
Assert.assertEquals(expected, actual);
}
@Test
public void testParseOffset() throws ParseException {
DateParser parser = getInstance(YMD_SLASH);
final Date date = parser.parse("Today is 2015/07/04", new ParsePosition(9));
final Calendar cal = Calendar.getInstance();
cal.clear();
cal.set(2015, Calendar.JULY, 4);
Assert.assertEquals(cal.getTime(), date);
}
}

View File

@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.Serializable;
import java.text.FieldPosition;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@ -30,8 +31,8 @@ import java.util.Locale;
import java.util.TimeZone;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.test.SystemDefaultsSwitch;
import org.apache.commons.lang3.test.SystemDefaults;
import org.apache.commons.lang3.test.SystemDefaultsSwitch;
import org.junit.Rule;
import org.junit.Test;
@ -364,4 +365,58 @@ public class FastDatePrinterTest {
assertEquals("calendar", "2009-10-16T07:42:16 +0100", value);
}
}
@Test
public void testHourFormats() {
Calendar calendar = Calendar.getInstance();
calendar.clear();
DatePrinter printer = getInstance("K k H h");
calendar.set(Calendar.HOUR_OF_DAY, 0);
assertEquals("0 24 0 12", printer.format(calendar));
calendar.set(Calendar.HOUR_OF_DAY, 12);
assertEquals("0 12 12 12", printer.format(calendar));
calendar.set(Calendar.HOUR_OF_DAY, 23);
assertEquals("11 23 23 11", printer.format(calendar));
}
@Test
public void testStringBufferOptions() {
final DatePrinter format = getInstance("yyyy-MM-dd HH:mm:ss.SSS Z", TimeZone.getTimeZone("GMT"));
Calendar calendar = Calendar.getInstance();
StringBuffer sb = new StringBuffer();
String expected = format.format(calendar, sb, new FieldPosition(0)).toString();
sb.setLength(0);
assertEquals(expected, format.format(calendar, sb).toString());
sb.setLength(0);
Date date = calendar.getTime();
assertEquals(expected, format.format(date, sb, new FieldPosition(0)).toString());
sb.setLength(0);
assertEquals(expected, format.format(date, sb).toString());
sb.setLength(0);
long epoch = date.getTime();
assertEquals(expected, format.format(epoch, sb, new FieldPosition(0)).toString());
sb.setLength(0);
assertEquals(expected, format.format(epoch, sb).toString());
}
@Test
public void testAppendableOptions() {
final DatePrinter format = getInstance("yyyy-MM-dd HH:mm:ss.SSS Z", TimeZone.getTimeZone("GMT"));
Calendar calendar = Calendar.getInstance();
StringBuilder sb = new StringBuilder();
String expected = format.format(calendar, sb).toString();
sb.setLength(0);
Date date = calendar.getTime();
assertEquals(expected, format.format(date, sb).toString());
sb.setLength(0);
long epoch = date.getTime();
assertEquals(expected, format.format(epoch, sb).toString());
}
}