Repository: pingcap/tidb (Go)

Issue:
StrToDate handling of %h(12) is not as expected
## Bug Report

Please answer these questions before submitting your issue. Thanks!

### 1. Minimal reproduce step (Required)
SELECT STR_TO_DATE('01,5,2013 12:30:17','%d,%m,%Y %h:%i:%s');
<!-- a step by step guide for reproducing the bug. -->

### 2. What did you expect to see? (Required)
mysql 8.0.17
2013-05-01 00:30:17
### 3. What did you see instead (Required)
2013-05-01 12:30:17
### 4. Affected version (Required)

<!-- v3.0.0, v4.0.0, etc -->
v4.0.0
### 5. Root Cause Analysis

<!-- should be filled by the investigator before it's closed -->



Discussion:

Patch:
diff --git a/types/time.go b/types/time.go
index f6c43d9b309b2..4f3e3203272b1 100644
--- a/types/time.go
+++ b/types/time.go
@@ -2498,6 +2498,10 @@ func mysqlTimeFix(t *CoreTime, ctx map[string]int) error {
 		if valueAMorPm == constForPM {
 			t.setHour(t.getHour() + 12)
 		}
+	} else {
+		if _, ok := ctx["%h"]; ok && t.Hour() == 12 {
+			t.setHour(0)
+		}
 	}
 	return nil
 }
@@ -2703,6 +2707,10 @@ func time12Hour(t *CoreTime, input string, ctx map[string]int) (string, bool) {
 	if !succ || hour > 12 || hour == 0 || input[2] != ':' {
 		return input, false
 	}
+	// 12:34:56 AM -> 00:34:56
+	if hour == 12 {
+		hour = 0
+	}
 
 	minute, succ := parseDigits(input[3:], 2)
 	if !succ || minute > 59 || input[5] != ':' {
@@ -2826,6 +2834,7 @@ func hour12Numeric(t *CoreTime, input string, ctx map[string]int) (string, bool)
 		return input, false
 	}
 	t.setHour(uint8(v))
+	ctx["%h"] = v
 	return input[length:], true
 }
 


Test patch:
diff --git a/types/format_test.go b/types/format_test.go
index 17e15c7c4ee2b..7dac7bd45105f 100644
--- a/types/format_test.go
+++ b/types/format_test.go
@@ -88,10 +88,12 @@ func (s *testTimeSuite) TestStrToDate(c *C) {
 		{`May 01, 2013`, `%M %d,%Y`, types.FromDate(2013, 5, 1, 0, 0, 0, 0)},
 		{`a09:30:17`, `a%h:%i:%s`, types.FromDate(0, 0, 0, 9, 30, 17, 0)},
 		{`09:30:17a`, `%h:%i:%s`, types.FromDate(0, 0, 0, 9, 30, 17, 0)},
+		{`12:43:24`, `%h:%i:%s`, types.FromDate(0, 0, 0, 0, 43, 24, 0)},
 		{`abc`, `abc`, types.ZeroCoreTime},
 		{`09`, `%m`, types.FromDate(0, 9, 0, 0, 0, 0, 0)},
 		{`09`, `%s`, types.FromDate(0, 0, 0, 0, 0, 9, 0)},
-		{`12:43:24 AM`, `%r`, types.FromDate(0, 0, 0, 12, 43, 24, 0)},
+		{`12:43:24 AM`, `%r`, types.FromDate(0, 0, 0, 0, 43, 24, 0)},
+		{`12:43:24 PM`, `%r`, types.FromDate(0, 0, 0, 12, 43, 24, 0)},
 		{`11:43:24 PM`, `%r`, types.FromDate(0, 0, 0, 23, 43, 24, 0)},
 		{`00:12:13`, `%T`, types.FromDate(0, 0, 0, 0, 12, 13, 0)},
 		{`23:59:59`, `%T`, types.FromDate(0, 0, 0, 23, 59, 59, 0)},
@@ -129,9 +131,8 @@ func (s *testTimeSuite) TestStrToDate(c *C) {
 	}{
 		{`04/31/2004`, `%m/%d/%Y`},
 		{`a09:30:17`, `%h:%i:%s`}, // format mismatch
-		{`12:43:24 PM`, `%r`},
-		{`12:43:24`, `%r`}, // no PM or AM followed
-		{`23:60:12`, `%T`}, // invalid minute
+		{`12:43:24`, `%r`},        // no PM or AM followed
+		{`23:60:12`, `%T`},        // invalid minute
 		{`18`, `%l`},
 		{`00:21:22 AM`, `%h:%i:%s %p`},
 		{`100/10/22`, `%y/%m/%d`},
@@ -139,8 +140,8 @@ func (s *testTimeSuite) TestStrToDate(c *C) {
 		{"2010-11-12 13 am", `%Y-%m-%d %h %p`},
 		{"2010-11-12 0 am", `%Y-%m-%d %h %p`},
 	}
-	for _, tt := range errTests {
+	for i, tt := range errTests {
 		var t types.Time
-		c.Assert(t.StrToDate(sc, tt.input, tt.format), IsFalse)
+		c.Assert(t.StrToDate(sc, tt.input, tt.format), IsFalse, Commentf("no.%d failed", i))
 	}
 }