You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flink.apache.org by ja...@apache.org on 2020/04/08 03:12:40 UTC
[flink] branch master updated: [FLINK-16632][table-planner-blink]
Fix SqlDateTimeUtils#toSqlTimestamp(String,
String) may yield incorrect result
This is an automated email from the ASF dual-hosted git repository.
jark pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink.git
The following commit(s) were added to refs/heads/master by this push:
new dd6d40f [FLINK-16632][table-planner-blink] Fix SqlDateTimeUtils#toSqlTimestamp(String, String) may yield incorrect result
dd6d40f is described below
commit dd6d40fd82b5ac945a95783f1a50cd35fdeadbb1
Author: Zhenghua Gao <do...@gmail.com>
AuthorDate: Wed Apr 8 11:12:12 2020 +0800
[FLINK-16632][table-planner-blink] Fix SqlDateTimeUtils#toSqlTimestamp(String, String) may yield incorrect result
This closes #11654
---
.../planner/expressions/TemporalTypesTest.scala | 20 ++++++++-
.../table/runtime/functions/SqlDateTimeUtils.java | 47 +++++++++++++++++-----
2 files changed, 54 insertions(+), 13 deletions(-)
diff --git a/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/planner/expressions/TemporalTypesTest.scala b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/planner/expressions/TemporalTypesTest.scala
index 42eb097..dfb977f 100644
--- a/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/planner/expressions/TemporalTypesTest.scala
+++ b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/planner/expressions/TemporalTypesTest.scala
@@ -118,8 +118,11 @@ class TemporalTypesTest extends ExpressionTestBase {
testSqlApi(
"CAST('1999-9-10 05:20:10.123456' AS TIMESTAMP)",
- "1999-09-10 05:20:10.123456"
- )
+ "1999-09-10 05:20:10.123456")
+
+ testSqlApi(
+ "CAST('1999-9-10' AS TIMESTAMP)",
+ "1999-09-10 00:00:00.000000")
}
@Test
@@ -1122,6 +1125,19 @@ class TemporalTypesTest extends ExpressionTestBase {
testSqlApi("TO_TIMESTAMP('abc')", "null")
+ // TO_TIMESTAMP should complement YEAR/MONTH/DAY/HOUR/MINUTE/SECOND/NANO_OF_SECOND
+ testSqlApi(
+ "TO_TIMESTAMP('2000020210', 'yyyyMMddHH')",
+ "2000-02-02 10:00:00.000")
+
+ testSqlApi(
+ "TO_TIMESTAMP('20000202 59:59.1234567', 'yyyyMMdd mm:ss.SSSSSSS')",
+ "2000-02-02 00:59:59.1234567")
+
+ testSqlApi(
+ "TO_TIMESTAMP('1234567', 'SSSSSSS')",
+ "1970-01-01 00:00:00.1234567")
+
// CAST between two TIMESTAMPs
testSqlApi(
"CAST(TIMESTAMP '1970-01-01 00:00:00.123456789' AS TIMESTAMP(6))",
diff --git a/flink-table/flink-table-runtime-blink/src/main/java/org/apache/flink/table/runtime/functions/SqlDateTimeUtils.java b/flink-table/flink-table-runtime-blink/src/main/java/org/apache/flink/table/runtime/functions/SqlDateTimeUtils.java
index a64ff98..42f3308 100644
--- a/flink-table/flink-table-runtime-blink/src/main/java/org/apache/flink/table/runtime/functions/SqlDateTimeUtils.java
+++ b/flink-table/flink-table-runtime-blink/src/main/java/org/apache/flink/table/runtime/functions/SqlDateTimeUtils.java
@@ -45,9 +45,18 @@ import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.TimeZone;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoField.YEAR;
+
/**
* Utility functions for datetime types: date, time, timestamp.
* Currently, it is a bit messy putting date time functions in various classes because
@@ -245,19 +254,35 @@ public class SqlDateTimeUtils {
DateTimeFormatter formatter = DATETIME_FORMATTER_CACHE.get(format);
try {
- if (dateStr.length() == 10) {
- // Just a LocalDate
- LocalDate ld = LocalDate.parse(dateStr, formatter);
- return SqlTimestamp.fromLocalDateTime(LocalDateTime.of(ld, LocalTime.MIDNIGHT));
- } else {
- LocalDateTime ldt = LocalDateTime.parse(dateStr, formatter);
- return SqlTimestamp.fromLocalDateTime(ldt);
- }
+ TemporalAccessor accessor = formatter.parse(dateStr);
+ // complement year with 1970
+ int year = accessor.isSupported(YEAR) ? accessor.get(YEAR) : 1970;
+ // complement month with 1
+ int month = accessor.isSupported(MONTH_OF_YEAR) ? accessor.get(MONTH_OF_YEAR) : 1;
+ // complement day with 1
+ int day = accessor.isSupported(DAY_OF_MONTH) ? accessor.get(DAY_OF_MONTH) : 1;
+ // complement hour with 0
+ int hour = accessor.isSupported(HOUR_OF_DAY) ? accessor.get(HOUR_OF_DAY) : 0;
+ // complement minute with 0
+ int minute = accessor.isSupported(MINUTE_OF_HOUR) ? accessor.get(MINUTE_OF_HOUR) : 0;
+ // complement second with 0
+ int second = accessor.isSupported(SECOND_OF_MINUTE) ? accessor.get(SECOND_OF_MINUTE) : 0;
+ // complement nano_of_second with 0
+ int nanoOfSecond = accessor.isSupported(NANO_OF_SECOND) ? accessor.get(NANO_OF_SECOND) : 0;
+ LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, minute, second, nanoOfSecond);
+ return SqlTimestamp.fromLocalDateTime(ldt);
} catch (DateTimeParseException e) {
- // fall back to support cases like '1999-9-10 05:20:10'
+ // fall back to support cases like '1999-9-10 05:20:10' or '1999-9-10'
try {
- Timestamp ts = Timestamp.valueOf(dateStr);
- return SqlTimestamp.fromTimestamp(ts);
+ dateStr = dateStr.trim();
+ int space = dateStr.indexOf(' ');
+ if (space >= 0) {
+ Timestamp ts = Timestamp.valueOf(dateStr);
+ return SqlTimestamp.fromTimestamp(ts);
+ } else {
+ java.sql.Date dt = java.sql.Date.valueOf(dateStr);
+ return SqlTimestamp.fromLocalDateTime(LocalDateTime.of(dt.toLocalDate(), LocalTime.MIDNIGHT));
+ }
} catch (IllegalArgumentException ie) {
return null;
}