/** * Please feel free to experiment - not only wrong data but sometimes number format exceptions... */ public class SimpleDateTest { static SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yyyy"); static String testdata[] = { "01-Jan-1999", "14-Feb-2001", "31-Dec-2007" }; /** * Test method for SDF. */ @Test public void testParse() { Runnable r[] = new Runnable[testdata.length]; for (int i = 0; i < r.length; i++) { final int i2 = i; r[i] = new Runnable() { public void run() { try { for (int j = 0; j < 1000; j++) { String str = testdata[i2]; String str2 = null; // synchronized(df) { Date d = df.parse(str); str2 = df.format(d); } Assert.assertEquals("date conversion failed after " + j + " iterations.", str, str2); } } catch (ParseException e) { throw new RuntimeException("parse failed"); } } }; new Thread(r[i]).start(); } } }
Possible outputs are:
Exception in thread "Thread-0" junit.framework.ComparisonFailure: date conversion failed after 0 iterations. expected:<[01-Jan-1999]> but was:<[14-Feb-2001]> at junit.framework.Assert.assertEquals(Assert.java:85)
Exception in thread "Thread-0" Exception in thread "Thread-1" java.lang.NumberFormatException: For input string: "19992001.E199920014E"
Exception in thread "Thread-0" java.lang.NumberFormatException: multiple points at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)
Exception in thread "Thread-0" java.lang.NumberFormatException: For input string: "" at java.lang.NumberFormatException.forInputString(Unknown Source)
And solution is synchronize usage of SimpleDateFormat, use ThreadLocal like here: ThreadSafeSimpleDateFormat:
tsd
or my last findings use improved version of ThreadLocal that creates HashMaps of SDF inside: SafeSimpleDateFormat
public class SafeSimpleDateFormat { private final String _format; private static final ThreadLocal<Map<String, SimpleDateFormat>> _dateFormats = new ThreadLocal<Map<String, SimpleDateFormat>>() { public Map<String, SimpleDateFormat> initialValue() { return new HashMap<String, SimpleDateFormat>(); } }; private SimpleDateFormat getDateFormat(String format) { Map<String, SimpleDateFormat> formatters = _dateFormats.get(); SimpleDateFormat formatter = formatters.get(format); if (formatter == null) { formatter = new SimpleDateFormat(format); formatters.put(format, formatter); } return formatter; } public SafeSimpleDateFormat(String format) { _format = format; } public String format(Date date) { return getDateFormat(_format).format(date); } public String format(Object date) { return getDateFormat(_format).format(date); } public Date parse(String day) throws ParseException { return getDateFormat(_format).parse(day); } public void setTimeZone(TimeZone tz) { getDateFormat(_format).setTimeZone(tz); } public void setCalendar(Calendar cal) { getDateFormat(_format).setCalendar(cal); } public void setNumberFormat(NumberFormat format) { getDateFormat(_format).setNumberFormat(format); } public void setLenient(boolean lenient) { getDateFormat(_format).setLenient(lenient); } public void setDateFormatSymbols(DateFormatSymbols symbols) { getDateFormat(_format).setDateFormatSymbols(symbols); } public void set2DigitYearStart(Date date) { getDateFormat(_format).set2DigitYearStart(date); } }
No comments:
Post a Comment