Index: DateUtils.java =================================================================== --- DateUtils.java (revision 545710) +++ DateUtils.java (working copy) @@ -35,7 +35,6 @@ import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; -import java.util.Locale; import java.util.TimeZone; /** @@ -149,15 +148,10 @@ dateValue = dateValue.substring (1, dateValue.length() - 1); } - SimpleDateFormat dateParser = null; for (int i = 0; i < dateFormats.length; i++) { - if (dateParser == null) { - dateParser = new SimpleDateFormat(dateFormats[i], Locale.US); - dateParser.setTimeZone(TimeZone.getTimeZone("GMT")); - dateParser.set2DigitYearStart(startDate); - } else { - dateParser.applyPattern(dateFormats[i]); - } + SimpleDateFormat dateParser = SimpleDateFormatFactory.formatFor(dateFormats[i]); + dateParser.set2DigitYearStart(startDate); + try { return dateParser.parse(dateValue); } catch (ParseException pe) { @@ -198,8 +192,7 @@ if (date == null) throw new IllegalArgumentException("date is null"); if (pattern == null) throw new IllegalArgumentException("pattern is null"); - SimpleDateFormat formatter = new SimpleDateFormat(pattern, Locale.US); - formatter.setTimeZone(GMT); + SimpleDateFormat formatter = SimpleDateFormatFactory.formatFor(pattern); return formatter.format(date); } Index: SimpleDateFormatFactory.java =================================================================== --- SimpleDateFormatFactory.java +++ SimpleDateFormatFactory.java @@ -0,0 +1,48 @@ +package org.apache.http.util; + +import java.text.SimpleDateFormat; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; + +/** + * A factory for {@link SimpleDateFormat}s. The instances are stored in a + * threadlocal way because SimpleDateFormat is not threadsafe as noted in + * {@link SimpleDateFormat its javadoc}. + * + * @author Daniel Mueller + */ +final class SimpleDateFormatFactory { + + private static final ThreadLocal threadlocalFormats = new ThreadLocal() { + @Override + protected Object initialValue() { + return new HashMap(); + } + }; + + /** + * creates a {@link SimpleDateFormat} for the requested format string. + * + * @param dateformat + * a non-null format String according to + * {@link SimpleDateFormat}. The format is not checked against + * null since all paths go through + * {@link DateUtils}. + * @return the requested format. This simple dateformat should not be used + * to {@link SimpleDateFormat#applyPattern(String) apply} to a + * different pattern. + */ + public static SimpleDateFormat formatFor(String pattern) { + Map formats = (Map) threadlocalFormats.get(); + SimpleDateFormat format = (SimpleDateFormat) formats.get(pattern); + if (format == null) { + format = new SimpleDateFormat(pattern, Locale.US); + format.setTimeZone(TimeZone.getTimeZone("GMT")); + formats.put(pattern, format); + } + + return format; + } +}