diff --git a/expression/builtin_time_test.go b/expression/builtin_time_test.go index 77fe3ae06ea74..0d5feb1340d58 100644 --- a/expression/builtin_time_test.go +++ b/expression/builtin_time_test.go @@ -1411,6 +1411,15 @@ func (s *testEvaluatorSuite) TestStrToDate(c *C) { {"15-01-2001 1:9:8.999", "%d-%m-%Y %H:%i:%S.%f", true, time.Date(2001, 1, 15, 1, 9, 8, 999000000, time.Local)}, {"2003-01-02 10:11:12 PM", "%Y-%m-%d %H:%i:%S %p", false, time.Time{}}, {"10:20:10AM", "%H:%i:%S%p", false, time.Time{}}, + // test %@(skip alpha), %#(skip number), %.(skip punct) + {"2020-10-10ABCD", "%Y-%m-%d%@", true, time.Date(2020, 10, 10, 0, 0, 0, 0, time.Local)}, + {"2020-10-101234", "%Y-%m-%d%#", true, time.Date(2020, 10, 10, 0, 0, 0, 0, time.Local)}, + {"2020-10-10....", "%Y-%m-%d%.", true, time.Date(2020, 10, 10, 0, 0, 0, 0, time.Local)}, + {"2020-10-10.1", "%Y-%m-%d%.%#%@", true, time.Date(2020, 10, 10, 0, 0, 0, 0, time.Local)}, + {"abcd2020-10-10.1", "%@%Y-%m-%d%.%#%@", true, time.Date(2020, 10, 10, 0, 0, 0, 0, time.Local)}, + {"abcd-2020-10-10.1", "%@-%Y-%m-%d%.%#%@", true, time.Date(2020, 10, 10, 0, 0, 0, 0, time.Local)}, + {"2020-10-10", "%Y-%m-%d%@", true, time.Date(2020, 10, 10, 0, 0, 0, 0, time.Local)}, + {"2020-10-10abcde123abcdef", "%Y-%m-%d%@%#", true, time.Date(2020, 10, 10, 0, 0, 0, 0, time.Local)}, } fc := funcs[ast.StrToDate] diff --git a/types/time.go b/types/time.go index 1358d1b47ef1b..615bb86ed6437 100644 --- a/types/time.go +++ b/types/time.go @@ -2896,6 +2896,9 @@ var dateFormatParserTable = map[string]dateFormatParser{ "%S": secondsNumeric, // Seconds (00..59) "%T": time24Hour, // Time, 24-hour (hh:mm:ss) "%Y": yearNumericFourDigits, // Year, numeric, four digits + "%#": skipAllNums, // Skip all numbers + "%.": skipAllPunct, // Skip all punctation characters + "%@": skipAllAlpha, // Skip all alpha characters // Deprecated since MySQL 5.7.5 "%y": yearNumericTwoDigits, // Year, numeric (two digits) // TODO: Add the following... @@ -3276,3 +3279,39 @@ func DateTimeIsOverflow(sc *stmtctx.StatementContext, date Time) (bool, error) { inRange := (t.After(b) || t.Equal(b)) && (t.Before(e) || t.Equal(e)) return !inRange, nil } + +func skipAllNums(t *CoreTime, input string, ctx map[string]int) (string, bool) { + retIdx := 0 + for i, ch := range input { + if unicode.IsNumber(ch) { + retIdx = i + 1 + } else { + break + } + } + return input[retIdx:], true +} + +func skipAllPunct(t *CoreTime, input string, ctx map[string]int) (string, bool) { + retIdx := 0 + for i, ch := range input { + if unicode.IsPunct(ch) { + retIdx = i + 1 + } else { + break + } + } + return input[retIdx:], true +} + +func skipAllAlpha(t *CoreTime, input string, ctx map[string]int) (string, bool) { + retIdx := 0 + for i, ch := range input { + if unicode.IsLetter(ch) { + retIdx = i + 1 + } else { + break + } + } + return input[retIdx:], true +}