Skip to content

Commit

Permalink
Port test cases from mysql; Fix bug for parsing "03-01-02 8:11:2.1234…
Browse files Browse the repository at this point in the history
…56" with format "%Y-%m-%d %H:%i:%S.%#"

Signed-off-by: JaySon-Huang <[email protected]>
  • Loading branch information
JaySon-Huang committed May 25, 2021
1 parent 229f388 commit 4893a34
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 32 deletions.
24 changes: 9 additions & 15 deletions dbms/src/Common/MyTime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1267,21 +1267,15 @@ static std::tuple<size_t, int32_t> parseNDigits(const StringRef & view, const si

static std::tuple<size_t, int32_t> parseYearNDigits(const StringRef & view, const size_t pos, const size_t limit)
{
int32_t effective_count = 0;
int32_t effective_value = 0;
while (static_cast<size_t>(effective_count + 1) <= limit)
{
auto [step, num] = parseNDigits(view, pos, effective_count + 1);
if (step == 0)
break;
effective_count++;
effective_value = num;
}
if (effective_count == 0)
return std::make_tuple(effective_count, 0);
else if (effective_count <= 2)
effective_value = adjustYear(effective_value);
return std::make_tuple(effective_count, effective_value);
// Try to parse a "year" within `limit` digits
size_t step = 0;
int32_t year = 0;
std::tie(step, year) = parseNDigits(view, pos, limit);
if (step == 0)
return std::make_tuple(step, 0);
else if (step <= 2)
year = adjustYear(year);
return std::make_tuple(step, year);
}

enum class ParseState
Expand Down
90 changes: 73 additions & 17 deletions dbms/src/Common/tests/gtest_mytime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ try
{" 2/Jun", "%d/%b/%Y", MyDateTime{0, 6, 2, 0, 0, 0, 0}}, // More patterns than input string
{" liter", "lit era l", MyDateTime{0, 0, 0, 0, 0, 0, 0}}, // More patterns than input string
// Test case for empty input
{" ", " ", MyDateTime{0, 0, 0, 0, 0, 0, 0}},
{" ", " ", MyDateTime{0, 0, 0, 0, 0, 0, 0}}, //
{" ", "%d/%b/%Y", MyDateTime{0, 0, 0, 0, 0, 0, 0}},
// Prefix white spaces should be ignored
{" 2/Jun/2019 ", "%d/%b/%Y", MyDateTime{2019, 6, 2, 0, 0, 0, 0}},
Expand All @@ -248,8 +248,8 @@ try
MyDateTime{2016, 2, 30, 12, 34, 56, 123400}}, // Feb 30th (not exist in actual) is valid for parsing (in mariadb)
{"31/April/2016 12:34:56.", "%d/%M/%Y %H:%i:%s.%f", MyDateTime{2016, 4, 31, 12, 34, 56, 0}}, // April 31th (not exist in actual)
{"01,5,2013 9", "%d,%c,%Y %f", MyDateTime{2013, 5, 1, 0, 0, 0, 900000}},
{"01,52013", "%d,%c%Y", std::nullopt}, // %c will try to parse '52' as month and fail
{"01,5,2013", "%d,%c,%Y", MyDateTime{2013, 5, 1, 0, 0, 0, 0}},
{"01,52013", "%d,%c%Y", std::nullopt}, // %c will try to parse '52' as month and fail
{"01,5,2013", "%d,%c,%Y", MyDateTime{2013, 5, 1, 0, 0, 0, 0}}, //
{"01,5,2013 ", "%d,%c,%Y %f", MyDateTime{2013, 5, 1, 0, 0, 0, 0}},

/// Test cases for AM/PM set
Expand Down Expand Up @@ -280,17 +280,17 @@ try
{"12: 13:56 AM 13/05/2019", "%r%d/%c/%Y", MyDateTime{2019, 5, 13, 0, 13, 56, 0}},
{"12:13 :56 pm 13/05/2019", "%r %d/%c/%Y", MyDateTime{2019, 5, 13, 12, 13, 56, 0}},
{"11:13: 56pm 13/05/2019", "%r %d/%c/%Y", MyDateTime{2019, 5, 13, 23, 13, 56, 0}},
{"11:13:56a", "%r", std::nullopt}, // EOF while parsing "AM"/"PM"
{"11:13", "%r", MyDateTime{0, 0, 0, 11, 13, 0, 0}},
{"11:", "%r", MyDateTime{0, 0, 0, 11, 0, 0, 0}},
{"11:13:56a", "%r", std::nullopt}, // EOF while parsing "AM"/"PM"
{"11:13", "%r", MyDateTime{0, 0, 0, 11, 13, 0, 0}}, //
{"11:", "%r", MyDateTime{0, 0, 0, 11, 0, 0, 0}}, //
{"12", "%r", MyDateTime{0, 0, 0, 0, 0, 0, 0}},

/// Test cases for %T
{" 4 :13:56 13/05/2019", "%T %d/%c/%Y", MyDateTime{2019, 5, 13, 4, 13, 56, 0}},
{"23: 13:56 13/05/2019", "%T%d/%c/%Y", MyDateTime{2019, 5, 13, 23, 13, 56, 0}},
{"12:13 :56 13/05/2019", "%T %d/%c/%Y", MyDateTime{2019, 5, 13, 12, 13, 56, 0}},
{"19:13: 56 13/05/2019", "%T %d/%c/%Y", MyDateTime{2019, 5, 13, 19, 13, 56, 0}},
{"21:13", "%T", MyDateTime{0, 0, 0, 21, 13, 0, 0}},
{"21:13", "%T", MyDateTime{0, 0, 0, 21, 13, 0, 0}}, //
{"21:", "%T", MyDateTime{0, 0, 0, 21, 0, 0, 0}},

// mutiple chars between pattern
Expand All @@ -301,16 +301,15 @@ try
{"01/Feb /2016 ab cdefg 23: 45:54", "%d /%b/%Y abc defg %H:%i :%S", MyDateTime{2016, 2, 1, 23, 45, 54, 0}},

/// Cases collect from MySQL 8.0 document
{"01,5,2013", "%d,%m,%Y", MyDateTime{2013, 5, 1, 0, 0, 0, 0}},
{"May 1, 2013", "%M %d,%Y", MyDateTime{2013, 5, 1, 0, 0, 0, 0}},
{"a09:30:17", "a%h:%i:%s", MyDateTime{0, 0, 0, 9, 30, 17, 0}},
{"a09:30:17", "%h:%i:%s", std::nullopt},
{"09:30:17a", "%h:%i:%s", MyDateTime{0, 0, 0, 9, 30, 17, 0}},
{"abc", "abc", MyDateTime{0, 0, 0, 0, 0, 0, 0}},
{"9", "%m", MyDateTime{0, 9, 0, 0, 0, 0, 0}},
{"9", "%s", MyDateTime{0, 0, 0, 0, 0, 9, 0}},
// Range checking on the parts of date values is as described in Section 11.2.2, “The DATE, DATETIME, and TIMESTAMP Types”. This means, for example, that “zero” dates or dates with part values of 0 are permitted unless the SQL mode is set to disallow such values.
{"00/00/0000", "%m/%d/%Y", MyDateTime{0, 0, 0, 0, 0, 0, 0}},
{"01,5,2013", "%d,%m,%Y", MyDateTime{2013, 5, 1, 0, 0, 0, 0}}, //
{"May 1, 2013", "%M %d,%Y", MyDateTime{2013, 5, 1, 0, 0, 0, 0}}, //
{"a09:30:17", "a%h:%i:%s", MyDateTime{0, 0, 0, 9, 30, 17, 0}}, //
{"a09:30:17", "%h:%i:%s", std::nullopt}, //
{"09:30:17a", "%h:%i:%s", MyDateTime{0, 0, 0, 9, 30, 17, 0}}, //
{"abc", "abc", MyDateTime{0, 0, 0, 0, 0, 0, 0}}, //
{"9", "%m", MyDateTime{0, 9, 0, 0, 0, 0, 0}}, //
{"9", "%s", MyDateTime{0, 0, 0, 0, 0, 9, 0}}, //
{"00/00/0000", "%m/%d/%Y", MyDateTime{0, 0, 0, 0, 0, 0, 0}}, //
{"04/31/2004", "%m/%d/%Y", MyDateTime{2004, 4, 31, 0, 0, 0, 0}},

/// Below cases are ported from TiDB
Expand All @@ -337,6 +336,63 @@ try
{"abcd-2020-10-10.1", "%@-%Y-%m-%d%.%#%@", MyDateTime(2020, 10, 10, 0, 0, 0, 0)},
{"2020-10-10", "%Y-%m-%d%@", MyDateTime(2020, 10, 10, 0, 0, 0, 0)},
{"2020-10-10abcde123abcdef", "%Y-%m-%d%@%#", MyDateTime(2020, 10, 10, 0, 0, 0, 0)},

/// Cases ported from mysql testing by executing following SQL in mysql
/// create table t1 (date char(30) COLLATE latin1_bin, format char(30) COLLATE latin1_bin not null);
/// insert into t1 values (...),...
/// select if( str_to_date is not null, concat( '{"', date, '", "', format, '", ', concat( "MyDateTime{", year(str_to_date), date_format(str_to_date, ",%c,%e,"), hour(str_to_date), ",", minute(str_to_date), ",", second(str_to_date), ",", MICROSECOND(str_to_date), "}" ), '}, //' ), concat( '{"', date, '", "', format, '", std::nullopt}, //' )) as s from ( select date, format, str_to_date(date, format) as str_to_date from t1 ) a group by date, format, str_to_date order by date;
{"0003-01-02 8:11:2.123456", "%Y-%m-%d %H:%i:%S.%#", MyDateTime{3, 1, 2, 8, 11, 2, 0}}, //
{"03-01-02 8:11:2.123456", "%Y-%m-%d %H:%i:%S.%#", MyDateTime{2003, 1, 2, 8, 11, 2, 0}}, //
{"03-01-02 8:11:2.123456", "%y-%m-%d %H:%i:%S.%#", MyDateTime{2003, 1, 2, 8, 11, 2, 0}}, //
{"10:20:10", "%H:%i:%s", MyDateTime{0, 0, 0, 10, 20, 10, 0}}, //
{"10:20:10", "%T", MyDateTime{0, 0, 0, 10, 20, 10, 0}}, //
{"10:20:10", "%h:%i:%s.%f", MyDateTime{0, 0, 0, 10, 20, 10, 0}}, //
{"10:20:10.44AM", "%h:%i:%s.%f%p", MyDateTime{0, 0, 0, 10, 20, 10, 440000}}, //
{"10:20:10AM", "%h:%i:%s%p", MyDateTime{0, 0, 0, 10, 20, 10, 0}}, //
{"10:20:10AM", "%r", MyDateTime{0, 0, 0, 10, 20, 10, 0}}, //
{"15 MAY 2001", "%d %b %Y", MyDateTime{2001, 5, 15, 0, 0, 0, 0}}, //
// {"15 SEPTEMB 2001", "%d %M %Y", MyDateTime{2001, 9, 15, 0, 0, 0, 0}}, // The SEPTEMB is a broken string of 'SEPTEMBER', ignore this case
{"15 September 2001", "%d %M %Y", MyDateTime{2001, 9, 15, 0, 0, 0, 0}}, //
{"15-01-20", "%d-%m-%y", MyDateTime{2020, 1, 15, 0, 0, 0, 0}}, //
{"15-01-2001", "%d-%m-%Y %H:%i:%S", MyDateTime{2001, 1, 15, 0, 0, 0, 0}}, //
{"15-01-2001 12:59:58", "%d-%m-%Y %H:%i:%S", MyDateTime{2001, 1, 15, 12, 59, 58, 0}}, //
{"15-2001-1", "%d-%Y-%c", MyDateTime{2001, 1, 15, 0, 0, 0, 0}}, //
{"2003-01-02 01:11:12.12345AM", "%Y-%m-%d %h:%i:%S.%f%p", MyDateTime{2003, 1, 2, 1, 11, 12, 123450}}, //
{"2003-01-02 02:11:12.12345AM", "%Y-%m-%d %h:%i:%S.%f %p", MyDateTime{2003, 1, 2, 2, 11, 12, 123450}}, //
{"2003-01-02 10:11:12", "%Y-%m-%d %H:%i:%S", MyDateTime{2003, 1, 2, 10, 11, 12, 0}}, //
{"2003-01-02 10:11:12 PM", "%Y-%m-%d %h:%i:%S %p", MyDateTime{2003, 1, 2, 22, 11, 12, 0}}, //
{"2003-01-02 11:11:12Pm", "%Y-%m-%d %h:%i:%S%p", MyDateTime{2003, 1, 2, 23, 11, 12, 0}}, //
{"2003-01-02 12:11:12.12345 am", "%Y-%m-%d %h:%i:%S.%f%p", MyDateTime{2003, 1, 2, 0, 11, 12, 123450}}, //
// some cases that are not implemented
// {"060 2004", "%j %Y", MyDateTime{2004, 2, 29, 0, 0, 0, 0}}, //
// {"15th May 2001", "%D %b %Y", MyDateTime{2001, 5, 15, 0, 0, 0, 0}}, //
// {"4 53 1998", "%w %u %Y", MyDateTime{1998, 12, 31, 0, 0, 0, 0}}, //
// {"Sund 15 MAY 2001", "%W %d %b %Y", MyDateTime{2001, 5, 15, 0, 0, 0, 0}}, //
// {"Sunday 01 2001", "%W %v %x", MyDateTime{2001, 1, 7, 0, 0, 0, 0}}, //
// {"Sunday 15 MAY 2001", "%W %d %b %Y", MyDateTime{2001, 5, 15, 0, 0, 0, 0}}, //
// {"Thursday 53 1998", "%W %u %Y", MyDateTime{1998, 12, 31, 0, 0, 0, 0}}, //
// {"Tuesday 00 2002", "%W %U %Y", MyDateTime{2002, 1, 1, 0, 0, 0, 0}}, //
// {"Tuesday 52 2001", "%W %V %X", MyDateTime{2002, 1, 1, 0, 0, 0, 0}}, //
// Test 'maybe' date formats and 'strange but correct' results
{"03-01-02 10:11:12 PM", "%Y-%m-%d %h:%i:%S %p", MyDateTime{2003, 1, 2, 22, 11, 12, 0}}, //
{"10:20:10AM", "%h:%i:%s", MyDateTime{0, 0, 0, 10, 20, 10, 0}}, //
{"2003-01-02 10:11:12", "%Y-%m-%d %h:%i:%S", MyDateTime{2003, 1, 2, 10, 11, 12, 0}}, //
// Test wrong dates or converion specifiers
{"10:20:10AM", "%H:%i:%s%p", std::nullopt}, //
{"15 Ju 2001", "%d %M %Y", std::nullopt}, //
{"15 Septembei 2001", "%d %M %Y", std::nullopt}, //
{"2003-01-02 10:11:12 PM", "%Y-%m-%d %H:%i:%S %p", std::nullopt}, //
{"2003-01-02 10:11:12 PM", "%y-%m-%d %H:%i:%S %p", std::nullopt}, //
{"2003-01-02 10:11:12.123456", "%Y-%m-%d %h:%i:%S %p", std::nullopt}, //
{"2003-01-02 10:11:12AM", "%Y-%m-%d %h:%i:%S.%f %p", std::nullopt}, //
{"2003-01-02 10:11:12AN", "%Y-%m-%d %h:%i:%S%p", std::nullopt}, //
// {"7 53 1998", "%w %u %Y", std::nullopt}, //
// {"Sund 15 MA", "%W %d %b %Y", std::nullopt}, //
// {"Sunday 01 2001", "%W %v %X", std::nullopt}, //
// {"Thursdai 12 1998", "%W %u %Y", std::nullopt}, //
// {"Tuesday 52 2001", "%W %V %Y", std::nullopt}, //
// {"Tuesday 52 2001", "%W %V %x", std::nullopt}, //
// {"Tuesday 52 2001", "%W %u %x", std::nullopt}, //
};
auto result_formatter = MyDateTimeFormatter("%Y/%m/%d %T.%f");
size_t idx = 0;
Expand Down

0 comments on commit 4893a34

Please sign in to comment.