From 994493d1b3c76e5e057872bad93efd76c44cc0e5 Mon Sep 17 00:00:00 2001 From: Greg Messner Date: Tue, 16 Apr 2019 22:52:58 -0700 Subject: [PATCH] Removed use of JAXB DatatypeConverter (#327). --- .../java/org/gitlab4j/api/utils/ISO8601.java | 65 ++++++++++++------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/gitlab4j/api/utils/ISO8601.java b/src/main/java/org/gitlab4j/api/utils/ISO8601.java index 661d287c..6781d39f 100644 --- a/src/main/java/org/gitlab4j/api/utils/ISO8601.java +++ b/src/main/java/org/gitlab4j/api/utils/ISO8601.java @@ -2,28 +2,39 @@ package org.gitlab4j.api.utils; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.ChronoField; import java.util.Calendar; import java.util.Date; import java.util.Map; import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; -import javax.xml.bind.DatatypeConverter; - /** * This class provides utility methods for parsing and formatting ISO8601 formatted dates. */ public class ISO8601 { public static final String PATTERN = "yyyy-MM-dd'T'HH:mm:ssZ"; + public static final String MSEC_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; public static final String SPACEY_PATTERN = "yyyy-MM-dd HH:mm:ss Z"; + public static final String SPACEY_MSEC_PATTERN = "yyyy-MM-dd HH:mm:ss.SSS Z"; 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_MSEC_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; public static final String UTC_PATTERN = "yyyy-MM-dd HH:mm:ss 'UTC'"; - private static final String PATTERN_REGEX = "\\d\\d\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d[-+]\\d\\d\\d\\d"; - private static final String SPACEY_PATTERN_REGEX = "\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d [-+]\\d\\d\\d\\d"; + private static final DateTimeFormatter ODT_WITH_MSEC_PARSER = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd[['T'][ ]HH:mm:ss.SSS[ ][XXXXX][XXXX]]").toFormatter(); + private static final DateTimeFormatter ODT_PARSER = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd[['T'][ ]HH:mm:ss[.SSS][ ][X][XXX]]") + .parseDefaulting(ChronoField.HOUR_OF_DAY, 0) + .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0) + .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0) + .parseDefaulting(ChronoField.MILLI_OF_SECOND, 0) + .parseDefaulting(ChronoField.OFFSET_SECONDS, 0) + .toFormatter(); // Set up ThreadLocal storage to save a thread local SimpleDateFormat keyed with the format string private static final class SafeDateFormatter { @@ -116,39 +127,43 @@ public class ISO8601 { } /** - * Parses an ISO8601 formatted string a returns a Date instance. + * Parses an ISO8601 formatted string a returns an Instant instance. * * @param dateTimeString the ISO8601 formatted string - * @return a Date instance for the ISO8601 formatted string + * @return an Instant instance for the ISO8601 formatted string * @throws ParseException if the provided string is not in the proper format */ - public static Date toDate(String dateTimeString) throws ParseException { + public static Instant toInstant(String dateTimeString) throws ParseException { if (dateTimeString == null) { return (null); } dateTimeString = dateTimeString.trim(); - if (dateTimeString.endsWith("UTC")) { - return (SafeDateFormatter.getDateFormat(UTC_PATTERN).parse(dateTimeString)); + if (dateTimeString.endsWith("Z") || dateTimeString.endsWith("UTC")) { + return (Instant.parse(dateTimeString)); } else { - try { - Calendar cal = DatatypeConverter.parseDateTime(dateTimeString); - return (cal.getTime()); - } catch (Exception e) { - if (dateTimeString.matches(PATTERN_REGEX)) { - // Try using the ISO8601 format - return (SafeDateFormatter.getDateFormat(PATTERN).parse(dateTimeString)); - } else if (dateTimeString.matches(SPACEY_PATTERN_REGEX)) { - // Try using the invalid ISO8601 format with spaces, GitLab sometimes uses this - return (SafeDateFormatter.getDateFormat(SPACEY_PATTERN).parse(dateTimeString)); - } else { - throw e; - } - } + + OffsetDateTime odt = (dateTimeString.length() > 25 ? + OffsetDateTime.parse(dateTimeString, ODT_WITH_MSEC_PARSER) : + OffsetDateTime.parse(dateTimeString, ODT_PARSER)); + + return (odt.toInstant()); } } + /** + * Parses an ISO8601 formatted string a returns a Date instance. + * + * @param dateTimeString the ISO8601 formatted string + * @return a Date instance for the ISO8601 formatted string + * @throws ParseException if the provided string is not in the proper format + */ + public static Date toDate(String dateTimeString) throws ParseException { + Instant instant = toInstant(dateTimeString); + return (instant != null ? Date.from(instant) : null); + } + /** * Parses an ISO8601 formatted string a returns a Calendar instance. * @@ -159,6 +174,10 @@ public class ISO8601 { public static Calendar toCalendar(String dateTimeString) throws ParseException { Date date = toDate(dateTimeString); + if (date == null) { + return (null); + } + Calendar cal = Calendar.getInstance(); cal.setTime(date); return (cal); -- GitLab