Skip to content

Commit e2a2cc4

Browse files
WangXiangUSTCzz-jason
authored andcommitted
types: fix incorrect time fraction parsing method (#10001)
1 parent 9b4940b commit e2a2cc4

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
@@ -443,7 +443,13 @@ func (t Time) RoundFrac(sc *stmtctx.StatementContext, fsp int) (Time, error) {
443443

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

461+
// GetFracIndex finds the last '.' for get fracStr, index = -1 means fracStr not found.
462+
// but for format like '2019.01.01 00:00:00', the index should be -1.
463+
func GetFracIndex(s string) (index int) {
464+
index = -1
465+
for i := len(s) - 1; i >= 0; i-- {
466+
if unicode.IsPunct(rune(s[i])) {
467+
if s[i] == '.' {
468+
index = i
469+
}
470+
break
471+
}
472+
}
473+
474+
return index
475+
}
476+
455477
// RoundFrac rounds fractional seconds precision with new fsp and returns a new one.
456478
// We will use the “round half up” rule, e.g, >= 0.5 -> 1, < 0.5 -> 0,
457479
// so 2011:11:11 10:10:10.888888 round 0 -> 2011:11:11 10:10:11
@@ -640,9 +662,10 @@ func ParseDateFormat(format string) []string {
640662
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html.
641663
// The only delimiter recognized between a date and time part and a fractional seconds part is the decimal point.
642664
func splitDateTime(format string) (seps []string, fracStr string) {
643-
if i := strings.LastIndex(format, "."); i > 0 {
644-
fracStr = strings.TrimSpace(format[i+1:])
645-
format = format[:i]
665+
index := GetFracIndex(format)
666+
if index > 0 {
667+
fracStr = format[index+1:]
668+
format = format[:index]
646669
}
647670

648671
seps = ParseDateFormat(format)
@@ -727,6 +750,15 @@ func parseDatetime(sc *stmtctx.StatementContext, str string, fsp int, isFloat bo
727750
sc.AppendWarning(ErrTruncatedWrongValue.GenWithStackByArgs("datetime", str))
728751
err = nil
729752
}
753+
case 2:
754+
// YYYY-MM is not valid
755+
if len(fracStr) == 0 {
756+
return ZeroDatetime, errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(str))
757+
}
758+
759+
// YYYY-MM.DD, DD is treat as fracStr
760+
err = scanTimeArgs(append(seps, fracStr), &year, &month, &day)
761+
fracStr = ""
730762
case 3:
731763
// YYYY-MM-DD
732764
err = scanTimeArgs(seps, &year, &month, &day)

types/time_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ func (s *testTimeSuite) TestDateTime(c *C) {
6262
{"170102036", "2017-01-02 03:06:00"},
6363
{"170102039.", "2017-01-02 03:09:00"},
6464
{"170102037.11", "2017-01-02 03:07:11.00"},
65+
{"2018.01.01", "2018-01-01 00:00:00.00"},
66+
{"2018/01/01-00:00:00", "2018-01-01 00:00:00"},
67+
{"2018.01.01 00:00:00", "2018-01-01 00:00:00"},
6568
}
6669

6770
for _, test := range table {
@@ -83,6 +86,9 @@ func (s *testTimeSuite) TestDateTime(c *C) {
8386
{"2017-01-05 23:59:59.575601", 0, "2017-01-06 00:00:00"},
8487
{"2017-01-31 23:59:59.575601", 0, "2017-02-01 00:00:00"},
8588
{"2017-00-05 23:59:58.575601", 3, "2017-00-05 23:59:58.576"},
89+
{"2017.00.05 23:59:58.575601", 3, "2017-00-05 23:59:58.576"},
90+
{"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"},
8692
}
8793

8894
for _, test := range fspTbl {
@@ -103,6 +109,8 @@ func (s *testTimeSuite) TestDateTime(c *C) {
103109
"1000-09-31 00:00:00",
104110
"1001-02-29 00:00:00",
105111
"20170118.999",
112+
"2018-01",
113+
"2018.01",
106114
}
107115

108116
for _, test := range errTable {
@@ -152,6 +160,8 @@ func (s *testTimeSuite) TestDate(c *C) {
152160
{"2015-06-01 12:12:12", "2015-06-01"},
153161
{"0001-01-01 00:00:00", "0001-01-01"},
154162
{"0001-01-01", "0001-01-01"},
163+
{"2019.01.01", "2019-01-01"},
164+
{"2019/01/01", "2019-01-01"},
155165
}
156166

157167
for _, test := range table {
@@ -162,6 +172,7 @@ func (s *testTimeSuite) TestDate(c *C) {
162172

163173
errTable := []string{
164174
"0121231",
175+
"2019.01",
165176
}
166177

167178
for _, test := range errTable {
@@ -1307,3 +1318,18 @@ func (s *testTimeSuite) TestGetFormatType(c *C) {
13071318
c.Assert(isDuration, Equals, true)
13081319
c.Assert(isDate, Equals, false)
13091320
}
1321+
1322+
func (s *testTimeSuite) TestgetFracIndex(c *C) {
1323+
testCases := []struct {
1324+
str string
1325+
expectIndex int
1326+
}{
1327+
{"2019.01.01 00:00:00", -1},
1328+
{"2019.01.01 00:00:00.1", 19},
1329+
{"12345.6", 5},
1330+
}
1331+
for _, testCase := range testCases {
1332+
index := types.GetFracIndex(testCase.str)
1333+
c.Assert(index, Equals, testCase.expectIndex)
1334+
}
1335+
}

0 commit comments

Comments
 (0)