Commit b0e1aac8 authored by Greg Messner's avatar Greg Messner
Browse files

Now thread safe (#120).

parent 7eb714cd
...@@ -4,7 +4,9 @@ import java.text.ParseException; ...@@ -4,7 +4,9 @@ import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.bind.DatatypeConverter; import javax.xml.bind.DatatypeConverter;
...@@ -12,33 +14,37 @@ import javax.xml.bind.DatatypeConverter; ...@@ -12,33 +14,37 @@ import javax.xml.bind.DatatypeConverter;
* This class provides utility methods for parsing and formatting ISO8601 formatted dates. * This class provides utility methods for parsing and formatting ISO8601 formatted dates.
*/ */
public class ISO8601 { public class ISO8601 {
public static final String PATTERN = "yyyy-MM-dd'T'HH:mm:ssZ"; public static final String PATTERN = "yyyy-MM-dd'T'HH:mm:ssZ";
public static final String PATTERN_MSEC = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; public static final String PATTERN_MSEC = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
public static final String OUTPUT_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'"; public static final String OUTPUT_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'";
public static final String OUTPUT_MSEC_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; public static final String OUTPUT_MSEC_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
public static final String UTC_PATTERN = "yyyy-MM-dd HH:mm:ss 'UTC'"; public static final String UTC_PATTERN = "yyyy-MM-dd HH:mm:ss 'UTC'";
private static final SimpleDateFormat iso8601Format; // Set up ThreadLocal storage to save a thread local SimpleDateFormat keyed with the format stringf
private static final SimpleDateFormat iso8601MsecFormat; private static final class SafeDateFormatter {
private static final SimpleDateFormat iso8601OutputFormat;
private static final SimpleDateFormat iso8601OutputMsecFormat; private static final ThreadLocal<Map<String, SimpleDateFormat>> safeFormats = new ThreadLocal<Map<String, SimpleDateFormat>>() {
private static final SimpleDateFormat iso8601UtcFormat;
static { @Override
iso8601Format = new SimpleDateFormat(PATTERN); public Map<String, SimpleDateFormat> initialValue() {
iso8601Format.setLenient(true); return (new ConcurrentHashMap<>());
iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC")); }
iso8601MsecFormat = new SimpleDateFormat(PATTERN_MSEC); };
iso8601MsecFormat.setLenient(true);
iso8601MsecFormat.setTimeZone(TimeZone.getTimeZone("UTC")); private static SimpleDateFormat getDateFormat(String formatSpec) {
iso8601OutputFormat = new SimpleDateFormat(OUTPUT_PATTERN);
iso8601OutputFormat.setLenient(true); Map<String, SimpleDateFormat> formatMap = safeFormats.get();
iso8601OutputFormat.setTimeZone(TimeZone.getTimeZone("UTC")); SimpleDateFormat format = formatMap.get(formatSpec);
iso8601OutputMsecFormat = new SimpleDateFormat(OUTPUT_MSEC_PATTERN); if (format == null) {
iso8601OutputMsecFormat.setLenient(true); format = new SimpleDateFormat(formatSpec);
iso8601OutputMsecFormat.setTimeZone(TimeZone.getTimeZone("UTC")); format.setLenient(true);
iso8601UtcFormat = new SimpleDateFormat(UTC_PATTERN); format.setTimeZone(TimeZone.getTimeZone("UTC"));
iso8601UtcFormat.setLenient(true); formatMap.put(formatSpec, format);
iso8601UtcFormat.setTimeZone(TimeZone.getTimeZone("UTC")); }
return (format);
}
} }
/** /**
...@@ -47,7 +53,7 @@ public class ISO8601 { ...@@ -47,7 +53,7 @@ public class ISO8601 {
* @return a ISO8601 formatted string for the current date and time * @return a ISO8601 formatted string for the current date and time
*/ */
public static String getTimestamp() { public static String getTimestamp() {
return (iso8601Format.format(new Date())); return (SafeDateFormatter.getDateFormat(PATTERN).format(new Date()));
} }
/** /**
...@@ -57,7 +63,8 @@ public class ISO8601 { ...@@ -57,7 +63,8 @@ public class ISO8601 {
* @return a ISO8601 formatted string for the current date and time * @return a ISO8601 formatted string for the current date and time
*/ */
public static String getTimestamp(boolean withMsec) { public static String getTimestamp(boolean withMsec) {
return (withMsec ? iso8601MsecFormat.format(new Date()) : iso8601Format.format(new Date())); return (withMsec ? SafeDateFormatter.getDateFormat(PATTERN_MSEC).format(new Date()) :
SafeDateFormatter.getDateFormat(PATTERN).format(new Date()));
} }
/** /**
...@@ -89,7 +96,9 @@ public class ISO8601 { ...@@ -89,7 +96,9 @@ public class ISO8601 {
} }
long time = date.getTime(); long time = date.getTime();
return (withMsec && time % 1000 != 0 ? iso8601OutputMsecFormat.format(date) : iso8601OutputFormat.format(date)); return (withMsec && time % 1000 != 0 ?
SafeDateFormatter.getDateFormat(OUTPUT_MSEC_PATTERN).format(date) :
SafeDateFormatter.getDateFormat(OUTPUT_PATTERN).format(date));
} }
/** /**
...@@ -117,9 +126,7 @@ public class ISO8601 { ...@@ -117,9 +126,7 @@ public class ISO8601 {
dateTimeString = dateTimeString.trim(); dateTimeString = dateTimeString.trim();
if (dateTimeString.endsWith("UTC")) { if (dateTimeString.endsWith("UTC")) {
synchronized (iso8601UtcFormat) { return (SafeDateFormatter.getDateFormat(UTC_PATTERN).parse(dateTimeString));
return (iso8601UtcFormat.parse(dateTimeString));
}
} else { } else {
Calendar cal = DatatypeConverter.parseDateTime(dateTimeString); Calendar cal = DatatypeConverter.parseDateTime(dateTimeString);
return (cal.getTime()); return (cal.getTime());
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment