Skip to content

Commit bf9570a

Browse files
WangXiangUSTCzz-jason
authored andcommitted
types: fix incorrect time fraction parsing method (#9933)
1 parent 4c91f53 commit bf9570a

File tree

2 files changed

+62
-4
lines changed

2 files changed

+62
-4
lines changed

types/time.go

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,13 @@ func (t Time) RoundFrac(sc *stmtctx.StatementContext, fsp int) (Time, error) {
444444

445445
// GetFsp gets the fsp of a string.
446446
func GetFsp(s string) (fsp int) {
447-
fsp = len(s) - strings.LastIndex(s, ".") - 1
447+
index := GetFracIndex(s)
448+
if index < 0 {
449+
fsp = 0
450+
} else {
451+
fsp = len(s) - index - 1
452+
}
453+
448454
if fsp == len(s) {
449455
fsp = 0
450456
} else if fsp > 6 {
@@ -453,6 +459,22 @@ func GetFsp(s string) (fsp int) {
453459
return
454460
}
455461

462+
// GetFracIndex finds the last '.' for get fracStr, index = -1 means fracStr not found.
463+
// but for format like '2019.01.01 00:00:00', the index should be -1.
464+
func GetFracIndex(s string) (index int) {
465+
index = -1
466+
for i := len(s) - 1; i >= 0; i-- {
467+
if unicode.IsPunct(rune(s[i])) {
468+
if s[i] == '.' {
469+
index = i
470+
}
471+
break
472+
}
473+
}
474+
475+
return index
476+
}
477+
456478
// RoundFrac rounds fractional seconds precision with new fsp and returns a new one.
457479
// We will use the “round half up” rule, e.g, >= 0.5 -> 1, < 0.5 -> 0,
458480
// so 2011:11:11 10:10:10.888888 round 0 -> 2011:11:11 10:10:11
@@ -655,9 +677,10 @@ func ParseDateFormat(format string) []string {
655677
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html.
656678
// The only delimiter recognized between a date and time part and a fractional seconds part is the decimal point.
657679
func splitDateTime(format string) (seps []string, fracStr string) {
658-
if i := strings.LastIndex(format, "."); i > 0 {
659-
fracStr = strings.TrimSpace(format[i+1:])
660-
format = format[:i]
680+
index := GetFracIndex(format)
681+
if index > 0 {
682+
fracStr = format[index+1:]
683+
format = format[:index]
661684
}
662685

663686
seps = ParseDateFormat(format)
@@ -742,6 +765,15 @@ func parseDatetime(sc *stmtctx.StatementContext, str string, fsp int, isFloat bo
742765
sc.AppendWarning(ErrTruncatedWrongValue.GenWithStackByArgs("datetime", str))
743766
err = nil
744767
}
768+
case 2:
769+
// YYYY-MM is not valid
770+
if len(fracStr) == 0 {
771+
return ZeroDatetime, errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(str))
772+
}
773+
774+
// YYYY-MM.DD, DD is treat as fracStr
775+
err = scanTimeArgs(append(seps, fracStr), &year, &month, &day)
776+
fracStr = ""
745777
case 3:
746778
// YYYY-MM-DD
747779
err = scanTimeArgs(seps, &year, &month, &day)

types/time_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ func (s *testTimeSuite) TestDateTime(c *C) {
6464
{"170102037.11", "2017-01-02 03:07:11.00"},
6565
{"2018-01-01 18", "2018-01-01 18:00:00"},
6666
{"18-01-01 18", "2018-01-01 18:00:00"},
67+
{"2018.01.01", "2018-01-01 00:00:00.00"},
68+
{"2018.01.01 00:00:00", "2018-01-01 00:00:00"},
69+
{"2018/01/01-00:00:00", "2018-01-01 00:00:00"},
6770
}
6871

6972
for _, test := range table {
@@ -85,6 +88,9 @@ func (s *testTimeSuite) TestDateTime(c *C) {
8588
{"2017-01-05 23:59:59.575601", 0, "2017-01-06 00:00:00"},
8689
{"2017-01-31 23:59:59.575601", 0, "2017-02-01 00:00:00"},
8790
{"2017-00-05 23:59:58.575601", 3, "2017-00-05 23:59:58.576"},
91+
{"2017.00.05 23:59:58.575601", 3, "2017-00-05 23:59:58.576"},
92+
{"2017/00/05 23:59:58.575601", 3, "2017-00-05 23:59:58.576"},
93+
{"2017/00/05-23:59:58.575601", 3, "2017-00-05 23:59:58.576"},
8894
}
8995

9096
for _, test := range fspTbl {
@@ -105,6 +111,8 @@ func (s *testTimeSuite) TestDateTime(c *C) {
105111
"1000-09-31 00:00:00",
106112
"1001-02-29 00:00:00",
107113
"20170118.999",
114+
"2018-01",
115+
"2018.01",
108116
}
109117

110118
for _, test := range errTable {
@@ -154,6 +162,8 @@ func (s *testTimeSuite) TestDate(c *C) {
154162
{"2015-06-01 12:12:12", "2015-06-01"},
155163
{"0001-01-01 00:00:00", "0001-01-01"},
156164
{"0001-01-01", "0001-01-01"},
165+
{"2019.01.01", "2019-01-01"},
166+
{"2019/01/01", "2019-01-01"},
157167
}
158168

159169
for _, test := range table {
@@ -164,6 +174,7 @@ func (s *testTimeSuite) TestDate(c *C) {
164174

165175
errTable := []string{
166176
"0121231",
177+
"2019.01",
167178
}
168179

169180
for _, test := range errTable {
@@ -1311,3 +1322,18 @@ func (s *testTimeSuite) TestGetFormatType(c *C) {
13111322
c.Assert(isDuration, Equals, true)
13121323
c.Assert(isDate, Equals, false)
13131324
}
1325+
1326+
func (s *testTimeSuite) TestgetFracIndex(c *C) {
1327+
testCases := []struct {
1328+
str string
1329+
expectIndex int
1330+
}{
1331+
{"2019.01.01 00:00:00", -1},
1332+
{"2019.01.01 00:00:00.1", 19},
1333+
{"12345.6", 5},
1334+
}
1335+
for _, testCase := range testCases {
1336+
index := types.GetFracIndex(testCase.str)
1337+
c.Assert(index, Equals, testCase.expectIndex)
1338+
}
1339+
}

0 commit comments

Comments
 (0)