Skip to content

Commit b0e1aac

Browse files
committed
Now thread safe (#120).
1 parent 7eb714c commit b0e1aac

File tree

1 file changed

+34
-27
lines changed

1 file changed

+34
-27
lines changed

src/main/java/org/gitlab4j/api/utils/ISO8601.java

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,47 @@
44
import java.text.SimpleDateFormat;
55
import java.util.Calendar;
66
import java.util.Date;
7+
import java.util.Map;
78
import java.util.TimeZone;
9+
import java.util.concurrent.ConcurrentHashMap;
810

911
import javax.xml.bind.DatatypeConverter;
1012

1113
/**
1214
* This class provides utility methods for parsing and formatting ISO8601 formatted dates.
1315
*/
1416
public class ISO8601 {
17+
1518
public static final String PATTERN = "yyyy-MM-dd'T'HH:mm:ssZ";
1619
public static final String PATTERN_MSEC = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
1720
public static final String OUTPUT_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'";
1821
public static final String OUTPUT_MSEC_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
1922
public static final String UTC_PATTERN = "yyyy-MM-dd HH:mm:ss 'UTC'";
2023

21-
private static final SimpleDateFormat iso8601Format;
22-
private static final SimpleDateFormat iso8601MsecFormat;
23-
private static final SimpleDateFormat iso8601OutputFormat;
24-
private static final SimpleDateFormat iso8601OutputMsecFormat;
25-
private static final SimpleDateFormat iso8601UtcFormat;
26-
static {
27-
iso8601Format = new SimpleDateFormat(PATTERN);
28-
iso8601Format.setLenient(true);
29-
iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
30-
iso8601MsecFormat = new SimpleDateFormat(PATTERN_MSEC);
31-
iso8601MsecFormat.setLenient(true);
32-
iso8601MsecFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
33-
iso8601OutputFormat = new SimpleDateFormat(OUTPUT_PATTERN);
34-
iso8601OutputFormat.setLenient(true);
35-
iso8601OutputFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
36-
iso8601OutputMsecFormat = new SimpleDateFormat(OUTPUT_MSEC_PATTERN);
37-
iso8601OutputMsecFormat.setLenient(true);
38-
iso8601OutputMsecFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
39-
iso8601UtcFormat = new SimpleDateFormat(UTC_PATTERN);
40-
iso8601UtcFormat.setLenient(true);
41-
iso8601UtcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
24+
// Set up ThreadLocal storage to save a thread local SimpleDateFormat keyed with the format stringf
25+
private static final class SafeDateFormatter {
26+
27+
private static final ThreadLocal<Map<String, SimpleDateFormat>> safeFormats = new ThreadLocal<Map<String, SimpleDateFormat>>() {
28+
29+
@Override
30+
public Map<String, SimpleDateFormat> initialValue() {
31+
return (new ConcurrentHashMap<>());
32+
}
33+
};
34+
35+
private static SimpleDateFormat getDateFormat(String formatSpec) {
36+
37+
Map<String, SimpleDateFormat> formatMap = safeFormats.get();
38+
SimpleDateFormat format = formatMap.get(formatSpec);
39+
if (format == null) {
40+
format = new SimpleDateFormat(formatSpec);
41+
format.setLenient(true);
42+
format.setTimeZone(TimeZone.getTimeZone("UTC"));
43+
formatMap.put(formatSpec, format);
44+
}
45+
46+
return (format);
47+
}
4248
}
4349

4450
/**
@@ -47,7 +53,7 @@ public class ISO8601 {
4753
* @return a ISO8601 formatted string for the current date and time
4854
*/
4955
public static String getTimestamp() {
50-
return (iso8601Format.format(new Date()));
56+
return (SafeDateFormatter.getDateFormat(PATTERN).format(new Date()));
5157
}
5258

5359
/**
@@ -57,7 +63,8 @@ public static String getTimestamp() {
5763
* @return a ISO8601 formatted string for the current date and time
5864
*/
5965
public static String getTimestamp(boolean withMsec) {
60-
return (withMsec ? iso8601MsecFormat.format(new Date()) : iso8601Format.format(new Date()));
66+
return (withMsec ? SafeDateFormatter.getDateFormat(PATTERN_MSEC).format(new Date()) :
67+
SafeDateFormatter.getDateFormat(PATTERN).format(new Date()));
6168
}
6269

6370
/**
@@ -89,7 +96,9 @@ public static synchronized String toString(Date date, boolean withMsec) {
8996
}
9097

9198
long time = date.getTime();
92-
return (withMsec && time % 1000 != 0 ? iso8601OutputMsecFormat.format(date) : iso8601OutputFormat.format(date));
99+
return (withMsec && time % 1000 != 0 ?
100+
SafeDateFormatter.getDateFormat(OUTPUT_MSEC_PATTERN).format(date) :
101+
SafeDateFormatter.getDateFormat(OUTPUT_PATTERN).format(date));
93102
}
94103

95104
/**
@@ -117,9 +126,7 @@ public static Date toDate(String dateTimeString) throws ParseException {
117126

118127
dateTimeString = dateTimeString.trim();
119128
if (dateTimeString.endsWith("UTC")) {
120-
synchronized (iso8601UtcFormat) {
121-
return (iso8601UtcFormat.parse(dateTimeString));
122-
}
129+
return (SafeDateFormatter.getDateFormat(UTC_PATTERN).parse(dateTimeString));
123130
} else {
124131
Calendar cal = DatatypeConverter.parseDateTime(dateTimeString);
125132
return (cal.getTime());

0 commit comments

Comments
 (0)