Repository: pingcap/tidb (Go)

Issue:
`TIME_FORMAT` is not compatible with MySQL
## Bug Report

Please answer these questions before submitting your issue. Thanks!

1. What did you do?
If possible, provide a recipe for reproducing the error.
```
SELECT TIME_FORMAT("24:00:00", '%r');
SELECT TIME_FORMAT("25:00:00", '%r');
SELECT TIME_FORMAT("24:00:00", '%l %p');
```

2. What did you expect to see?
In Mysql
```
mysql> SELECT TIME_FORMAT("24:00:00", '%r');
+-------------------------------+
| TIME_FORMAT("24:00:00", '%r') |
+-------------------------------+
| 12:00:00 AM                   |
+-------------------------------+
1 row in set (0.00 sec)

mysql> SELECT TIME_FORMAT("25:00:00", '%r');
+-------------------------------+
| TIME_FORMAT("25:00:00", '%r') |
+-------------------------------+
| 01:00:00 AM                   |
+-------------------------------+
1 row in set (0.00 sec)

mysql> SELECT TIME_FORMAT("24:00:00", '%l %p');
+----------------------------------+
| TIME_FORMAT("24:00:00", '%l %p') |
+----------------------------------+
| 12 AM                            |
+----------------------------------+
1 row in set (0.00 sec)
```


3. What did you see instead?
In TiDB
```
mysql> SELECT TIME_FORMAT("24:00:00", '%r');
+-------------------------------+
| TIME_FORMAT("24:00:00", '%r') |
+-------------------------------+
| 12:00:00 PM                   |
+-------------------------------+
1 row in set (0.00 sec)

mysql> SELECT TIME_FORMAT("25:00:00", '%r');
+-------------------------------+
| TIME_FORMAT("25:00:00", '%r') |
+-------------------------------+
| 13:00:00 PM                   |
+-------------------------------+
1 row in set (0.00 sec)

mysql> SELECT TIME_FORMAT("24:00:00", '%l %p');
+----------------------------------+
| TIME_FORMAT("24:00:00", '%l %p') |
+----------------------------------+
| 0 AM                             |
+----------------------------------+
1 row in set (0.00 sec)
```


4. What version of TiDB are you using (`tidb-server -V` or run `select tidb_version();` on TiDB)?
```
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tidb_version()                                                                                                                                                                                                                                                                                                                           |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Release Version: v3.0.0-beta-227-g06183393e-dirty
Git Commit Hash: 06183393ed536aa248248b72d4bf9f5010947f66
Git Branch: master
UTC Build Time: 2019-03-15 08:22:53
GoVersion: go version go1.12 darwin/amd64
Race Enabled: false
TiKV Min Version: 2.1.0-alpha.1-ff3dd160846b7d1aed9079c389fc188f7f5ea13e
Check Table Before Drop: false |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
```




Discussion:

Patch:
diff --git a/types/time.go b/types/time.go
index 7969a867c496e..cb96bb917edda 100644
--- a/types/time.go
+++ b/types/time.go
@@ -1921,14 +1921,14 @@ func (t Time) convertDateFormat(b rune, buf *bytes.Buffer) error {
 		fmt.Fprintf(buf, "%d", t.Time.Hour())
 	case 'h', 'I':
 		t := t.Time.Hour()
-		if t == 0 || t == 12 {
+		if t%12 == 0 {
 			fmt.Fprintf(buf, "%02d", 12)
 		} else {
 			fmt.Fprintf(buf, "%02d", t%12)
 		}
 	case 'l':
 		t := t.Time.Hour()
-		if t == 0 || t == 12 {
+		if t%12 == 0 {
 			fmt.Fprintf(buf, "%d", 12)
 		} else {
 			fmt.Fprintf(buf, "%d", t%12)
@@ -1944,6 +1944,7 @@ func (t Time) convertDateFormat(b rune, buf *bytes.Buffer) error {
 		}
 	case 'r':
 		h := t.Time.Hour()
+		h %= 24
 		switch {
 		case h == 0:
 			fmt.Fprintf(buf, "%02d:%02d:%02d AM", 12, t.Time.Minute(), t.Time.Second())


Test patch:
diff --git a/expression/integration_test.go b/expression/integration_test.go
index d52d49651412e..bad171ee28de2 100644
--- a/expression/integration_test.go
+++ b/expression/integration_test.go
@@ -1515,6 +1515,12 @@ func (s *testIntegrationSuite) TestTimeBuiltin(c *C) {
 	result.Check(testkit.Rows("<nil>"))
 	result = tk.MustQuery("SELECT TIME_FORMAT(123, '%H:%i:%s %p');")
 	result.Check(testkit.Rows("00:01:23 AM"))
+	result = tk.MustQuery("SELECT TIME_FORMAT('24:00:00', '%r');")
+	result.Check(testkit.Rows("12:00:00 AM"))
+	result = tk.MustQuery("SELECT TIME_FORMAT('25:00:00', '%r');")
+	result.Check(testkit.Rows("01:00:00 AM"))
+	result = tk.MustQuery("SELECT TIME_FORMAT('24:00:00', '%l %p');")
+	result.Check(testkit.Rows("12 AM"))
 
 	// for date_format
 	result = tk.MustQuery(`SELECT DATE_FORMAT('2017-06-15', '%W %M %e %Y %r %y');`)