diff --git common/src/java/org/apache/hadoop/hive/common/type/Timestamp.java common/src/java/org/apache/hadoop/hive/common/type/Timestamp.java index a8b7b6d186..5c2e906c8a 100644 --- common/src/java/org/apache/hadoop/hive/common/type/Timestamp.java +++ common/src/java/org/apache/hadoop/hive/common/type/Timestamp.java @@ -17,6 +17,7 @@ */ package org.apache.hadoop.hive.common.type; +import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; @@ -75,9 +76,28 @@ private LocalDateTime localDateTime; + private static final LocalDateTime MIN_LOCALDATETIME = LocalDateTime.parse("0000-01-01 00:00:00", PARSE_FORMATTER); + private static final LocalDateTime MAX_LOCALDATETIME = LocalDateTime.parse("9999-12-31 23:59:59.999999999", PARSE_FORMATTER); + /* Private constructor */ private Timestamp(LocalDateTime localDateTime) { - this.localDateTime = localDateTime != null ? localDateTime : EPOCH; + setLocalDateTime(localDateTime != null ? localDateTime : EPOCH); + } + + private void setLocalDateTime(LocalDateTime localDateTime) { + if (valid(localDateTime)) { + this.localDateTime = localDateTime; + } else { + throw new DateTimeException("Timestamp value " + localDateTime + " out of range"); + } + } + + /** + * Valid range is years 0000-9999, and 0000 converts to 0001. + */ + private static boolean valid(LocalDateTime localDateTime) { + return localDateTime.compareTo(MIN_LOCALDATETIME) >= 0 && + localDateTime.compareTo(MAX_LOCALDATETIME) <= 0; } public Timestamp() { @@ -89,7 +109,7 @@ public Timestamp(Timestamp t) { } public void set(Timestamp t) { - this.localDateTime = t != null ? t.localDateTime : EPOCH; + setLocalDateTime(t != null ? t.localDateTime : EPOCH); } public String format(DateTimeFormatter formatter) { @@ -127,8 +147,7 @@ public void setTimeInSeconds(long epochSecond) { } public void setTimeInSeconds(long epochSecond, int nanos) { - localDateTime = LocalDateTime.ofEpochSecond( - epochSecond, nanos, ZoneOffset.UTC); + setLocalDateTime(LocalDateTime.ofEpochSecond(epochSecond, nanos, ZoneOffset.UTC)); } public long toEpochMilli() { @@ -136,14 +155,14 @@ public long toEpochMilli() { } public void setTimeInMillis(long epochMilli) { - localDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(epochMilli), ZoneOffset.UTC); + setLocalDateTime(LocalDateTime.ofInstant( + Instant.ofEpochMilli(epochMilli), ZoneOffset.UTC)); } public void setTimeInMillis(long epochMilli, int nanos) { - localDateTime = LocalDateTime + setLocalDateTime(LocalDateTime .ofInstant(Instant.ofEpochMilli(epochMilli), ZoneOffset.UTC) - .withNano(nanos); + .withNano(nanos)); } public int getNanos() { @@ -163,7 +182,10 @@ public static Timestamp valueOf(String s) { throw new IllegalArgumentException("Cannot create timestamp, parsing error"); } } - return new Timestamp(localDateTime); + if (valid(localDateTime)) { + return new Timestamp(localDateTime); + } + return null; } public static Timestamp ofEpochSecond(long epochSecond) { @@ -171,23 +193,33 @@ public static Timestamp ofEpochSecond(long epochSecond) { } public static Timestamp ofEpochSecond(long epochSecond, int nanos) { - return new Timestamp( - LocalDateTime.ofEpochSecond(epochSecond, nanos, ZoneOffset.UTC)); + LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(epochSecond, nanos, ZoneOffset.UTC); + if (valid(localDateTime)) { + return new Timestamp(localDateTime); + } + return null; } public static Timestamp ofEpochMilli(long epochMilli) { - return new Timestamp(LocalDateTime - .ofInstant(Instant.ofEpochMilli(epochMilli), ZoneOffset.UTC)); + LocalDateTime localDateTime = + LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMilli), ZoneOffset.UTC); + if (valid(localDateTime)) { + return new Timestamp(localDateTime); + } + return null; } public static Timestamp ofEpochMilli(long epochMilli, int nanos) { - return new Timestamp(LocalDateTime - .ofInstant(Instant.ofEpochMilli(epochMilli), ZoneOffset.UTC) - .withNano(nanos)); + LocalDateTime localDateTime = + LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMilli), ZoneOffset.UTC); + if (valid(localDateTime)) { + return new Timestamp(localDateTime); + } + return null; } public void setNanos(int nanos) { - localDateTime = localDateTime.withNano(nanos); + setLocalDateTime(localDateTime.withNano(nanos)); } public int getYear() { diff --git common/src/java/org/apache/hadoop/hive/common/type/TimestampUtils.java common/src/java/org/apache/hadoop/hive/common/type/TimestampUtils.java index f26f8ae01e..7527a5feaf 100644 --- common/src/java/org/apache/hadoop/hive/common/type/TimestampUtils.java +++ common/src/java/org/apache/hadoop/hive/common/type/TimestampUtils.java @@ -186,8 +186,12 @@ public static Timestamp stringToTimestamp(String s) { return Timestamp.valueOf( TimestampTZUtil.parse(s).getZonedDateTime().toLocalDateTime().toString()); } catch (IllegalArgumentException | DateTimeParseException eTZ) { - // Last attempt - return Timestamp.ofEpochMilli(Date.valueOf(s).toEpochMilli()); + try { + // Last attempt + return Timestamp.ofEpochMilli(Date.valueOf(s).toEpochMilli()); + } catch (IllegalArgumentException | DateTimeParseException | NullPointerException eTZ2) { + return null; + } } } }