Skip to content

Commit

Permalink
[FLINK-16632][table-planner-blink] Fix SqlDateTimeUtils#toSqlTimestam…
Browse files Browse the repository at this point in the history
…p(String, String) may yield incorrect result

This closes apache#11654
  • Loading branch information
docete committed Apr 8, 2020
1 parent 980e31d commit dd6d40f
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,18 @@
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
Expand Down Expand Up @@ -245,19 +254,35 @@ public static SqlTimestamp toSqlTimestamp(String dateStr, String format) {
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;
}
Expand Down

0 comments on commit dd6d40f

Please sign in to comment.