From fb6b47c3ed3853374cb98083f361faf33bbb3667 Mon Sep 17 00:00:00 2001 From: Piotr Findeisen Date: Fri, 9 Mar 2018 23:52:40 +0100 Subject: [PATCH 1/2] HIVE-18925: Prevent failure when JVM zone had change on 1970-01-01 This prevents static initializer failure if JVM zone did not observe 1970-01-01 00:00:00, while retaining original behavior for all other zones. --- .../src/java/org/apache/hive/common/util/TimestampParser.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/src/java/org/apache/hive/common/util/TimestampParser.java b/common/src/java/org/apache/hive/common/util/TimestampParser.java index 14b9ca0b44dc..3a80dc3a15f5 100644 --- a/common/src/java/org/apache/hive/common/util/TimestampParser.java +++ b/common/src/java/org/apache/hive/common/util/TimestampParser.java @@ -27,6 +27,7 @@ import java.util.regex.Pattern; import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; import org.joda.time.MutableDateTime; import org.joda.time.DateTimeFieldType; import org.joda.time.format.DateTimeFormat; @@ -46,7 +47,7 @@ public class TimestampParser { protected final static String[] stringArray = new String[] {}; protected final static String millisFormatString = "millis"; - protected final static DateTime startingDateValue = new DateTime(1970, 1, 1, 0, 0, 0, 0); + protected final static DateTime startingDateValue = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeZone.UTC).withZoneRetainFields(DateTimeZone.getDefault()); protected String[] formatStrings = null; protected DateTimeFormatter fmt = null; From f44bbe25c76bc299c34017c59eaceae68815f7da Mon Sep 17 00:00:00 2001 From: Piotr Findeisen Date: Sat, 24 Mar 2018 23:10:49 +0100 Subject: [PATCH 2/2] fixup! HIVE-18925: Prevent failure when JVM zone had change on 1970-01-01 --- .../hive/common/util/TimestampParser.java | 51 ++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/common/src/java/org/apache/hive/common/util/TimestampParser.java b/common/src/java/org/apache/hive/common/util/TimestampParser.java index 3a80dc3a15f5..f674b5d30bd8 100644 --- a/common/src/java/org/apache/hive/common/util/TimestampParser.java +++ b/common/src/java/org/apache/hive/common/util/TimestampParser.java @@ -23,11 +23,12 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; +import org.joda.time.IllegalInstantException; import org.joda.time.MutableDateTime; import org.joda.time.DateTimeFieldType; import org.joda.time.format.DateTimeFormat; @@ -36,6 +37,10 @@ import org.joda.time.format.DateTimeParser; import org.joda.time.format.DateTimeParserBucket; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkState; + /** * Timestamp parser using Joda DateTimeFormatter. Parser accepts 0 or more date time format * patterns. If no format patterns are provided it will default to the normal Timestamp parsing. @@ -47,7 +52,19 @@ public class TimestampParser { protected final static String[] stringArray = new String[] {}; protected final static String millisFormatString = "millis"; - protected final static DateTime startingDateValue = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeZone.UTC).withZoneRetainFields(DateTimeZone.getDefault()); + @Nullable + private final static DateTime startingDateValue = makeStartingDateValue(); + + @Nullable + private static DateTime makeStartingDateValue() { + try { + return new DateTime(1970, 1, 1, 0, 0, 0, 0); + } catch (IllegalInstantException e) { + // 1970-01-01 00:00:00 did not exist in some zones. In these zones, we need to take different, + // less optimal parsing route. + return null; + } + } protected String[] formatStrings = null; protected DateTimeFormatter fmt = null; @@ -79,7 +96,10 @@ public TimestampParser(String[] formatStrings) { parsers[idx] = DateTimeFormat.forPattern(formatString).getParser(); } } - fmt = new DateTimeFormatterBuilder().append(null, parsers).toFormatter(); + fmt = new DateTimeFormatterBuilder() + .append(null, parsers) + .toFormatter() + .withDefaultYear(1970); } } @@ -91,6 +111,20 @@ public TimestampParser(String[] formatStrings) { */ public Timestamp parseTimestamp(String strValue) throws IllegalArgumentException { if (fmt != null) { + Optional parsed = tryParseWithFormat(strValue); + if (parsed.isPresent()) { + return parsed.get(); + } + } + + // Otherwise try default timestamp parsing + return Timestamp.valueOf(strValue); + } + + private Optional tryParseWithFormat(String strValue) { + checkState(fmt != null); + + if (startingDateValue != null) { // reset value in case any date fields are missing from the date pattern MutableDateTime mdt = new MutableDateTime(startingDateValue); @@ -99,12 +133,17 @@ public Timestamp parseTimestamp(String strValue) throws IllegalArgumentException int ret = fmt.parseInto(mdt, strValue, 0); // Only accept parse results if we parsed the entire string if (ret == strValue.length()) { - return new Timestamp(mdt.getMillis()); + return Optional.of(new Timestamp(mdt.getMillis())); } + return Optional.empty(); } - // Otherwise try default timestamp parsing - return Timestamp.valueOf(strValue); + try { + DateTime dt = fmt.parseDateTime(strValue); + return Optional.of(new Timestamp(dt.getMillis())); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } } /**