Skip to content

Commit 6bc2416

Browse files
committed
fix: add toBinaryDateTime test
1 parent aa48110 commit 6bc2416

File tree

2 files changed

+132
-38
lines changed

2 files changed

+132
-38
lines changed

mysql/resultset_helper.go

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,44 +11,6 @@ import (
1111
"github.com/siddontang/go/hack"
1212
)
1313

14-
func toBinaryDateTime(t time.Time) ([]byte, error) {
15-
var buf bytes.Buffer
16-
17-
if t.IsZero() {
18-
return nil, nil
19-
}
20-
21-
year, month, day := t.Year(), t.Month(), t.Day()
22-
hour, min, sec := t.Hour(), t.Minute(), t.Second()
23-
nanosec := t.Nanosecond()
24-
25-
if nanosec > 0 {
26-
buf.WriteByte(byte(11))
27-
_ = binary.Write(&buf, binary.LittleEndian, uint16(year))
28-
buf.WriteByte(byte(month))
29-
buf.WriteByte(byte(day))
30-
buf.WriteByte(byte(hour))
31-
buf.WriteByte(byte(min))
32-
buf.WriteByte(byte(sec))
33-
_ = binary.Write(&buf, binary.LittleEndian, uint32(nanosec/1000))
34-
} else if hour > 0 || min > 0 || sec > 0 {
35-
buf.WriteByte(byte(7))
36-
_ = binary.Write(&buf, binary.LittleEndian, uint16(year))
37-
buf.WriteByte(byte(month))
38-
buf.WriteByte(byte(day))
39-
buf.WriteByte(byte(hour))
40-
buf.WriteByte(byte(min))
41-
buf.WriteByte(byte(sec))
42-
} else {
43-
buf.WriteByte(byte(4))
44-
_ = binary.Write(&buf, binary.LittleEndian, uint16(year))
45-
buf.WriteByte(byte(month))
46-
buf.WriteByte(byte(day))
47-
}
48-
49-
return buf.Bytes(), nil
50-
}
51-
5214
func FormatTextValue(value interface{}) ([]byte, error) {
5315
switch v := value.(type) {
5416
case int8:
@@ -88,6 +50,44 @@ func FormatTextValue(value interface{}) ([]byte, error) {
8850
}
8951
}
9052

53+
func toBinaryDateTime(t time.Time) ([]byte, error) {
54+
var buf bytes.Buffer
55+
56+
if t.IsZero() {
57+
return nil, nil
58+
}
59+
60+
year, month, day := t.Year(), t.Month(), t.Day()
61+
hour, min, sec := t.Hour(), t.Minute(), t.Second()
62+
nanosec := t.Nanosecond()
63+
64+
if nanosec > 0 {
65+
buf.WriteByte(byte(11))
66+
_ = binary.Write(&buf, binary.LittleEndian, uint16(year))
67+
buf.WriteByte(byte(month))
68+
buf.WriteByte(byte(day))
69+
buf.WriteByte(byte(hour))
70+
buf.WriteByte(byte(min))
71+
buf.WriteByte(byte(sec))
72+
_ = binary.Write(&buf, binary.LittleEndian, uint32(nanosec/1000))
73+
} else if hour > 0 || min > 0 || sec > 0 {
74+
buf.WriteByte(byte(7))
75+
_ = binary.Write(&buf, binary.LittleEndian, uint16(year))
76+
buf.WriteByte(byte(month))
77+
buf.WriteByte(byte(day))
78+
buf.WriteByte(byte(hour))
79+
buf.WriteByte(byte(min))
80+
buf.WriteByte(byte(sec))
81+
} else {
82+
buf.WriteByte(byte(4))
83+
_ = binary.Write(&buf, binary.LittleEndian, uint16(year))
84+
buf.WriteByte(byte(month))
85+
buf.WriteByte(byte(day))
86+
}
87+
88+
return buf.Bytes(), nil
89+
}
90+
9191
func formatBinaryValue(value interface{}) ([]byte, error) {
9292
switch v := value.(type) {
9393
case int8:

mysql/util_test.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package mysql
22

33
import (
4+
"encoding/binary"
5+
"fmt"
6+
"strings"
47
"testing"
8+
"time"
59

610
"github.com/stretchr/testify/require"
711
)
@@ -51,3 +55,93 @@ func TestFormatBinaryTime(t *testing.T) {
5155
require.Equal(t, test.Expect, string(got), "test case %v", test.Data)
5256
}
5357
}
58+
59+
// mysql driver parse binary datetime
60+
func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (time.Time, error) {
61+
switch num {
62+
case 0:
63+
return time.Time{}, nil
64+
case 4:
65+
return time.Date(
66+
int(binary.LittleEndian.Uint16(data[:2])), // year
67+
time.Month(data[2]), // month
68+
int(data[3]), // day
69+
0, 0, 0, 0,
70+
loc,
71+
), nil
72+
case 7:
73+
return time.Date(
74+
int(binary.LittleEndian.Uint16(data[:2])), // year
75+
time.Month(data[2]), // month
76+
int(data[3]), // day
77+
int(data[4]), // hour
78+
int(data[5]), // minutes
79+
int(data[6]), // seconds
80+
0,
81+
loc,
82+
), nil
83+
case 11:
84+
return time.Date(
85+
int(binary.LittleEndian.Uint16(data[:2])), // year
86+
time.Month(data[2]), // month
87+
int(data[3]), // day
88+
int(data[4]), // hour
89+
int(data[5]), // minutes
90+
int(data[6]), // seconds
91+
int(binary.LittleEndian.Uint32(data[7:11]))*1000, // nanoseconds
92+
loc,
93+
), nil
94+
}
95+
return time.Time{}, fmt.Errorf("invalid DATETIME packet length %d", num)
96+
}
97+
98+
func TestToBinaryDateTime(t *testing.T) {
99+
tests := []struct {
100+
name string
101+
input time.Time
102+
expected string
103+
}{
104+
{
105+
name: "Zero time",
106+
input: time.Time{},
107+
expected: "",
108+
},
109+
{
110+
name: "Date with nanoseconds",
111+
input: time.Date(2023, 10, 10, 10, 10, 10, 123456000, time.UTC),
112+
expected: "2023-10-10 10:10:10.123456 +0000 UTC",
113+
},
114+
{
115+
name: "Date with time",
116+
input: time.Date(2023, 10, 10, 10, 10, 10, 0, time.UTC),
117+
expected: "2023-10-10 10:10:10 +0000 UTC",
118+
},
119+
{
120+
name: "Date only",
121+
input: time.Date(2023, 10, 10, 0, 0, 0, 0, time.UTC),
122+
expected: "2023-10-10 00:00:00 +0000 UTC",
123+
},
124+
}
125+
126+
for _, tt := range tests {
127+
t.Run(tt.name, func(t *testing.T) {
128+
result, err := toBinaryDateTime(tt.input)
129+
if err != nil {
130+
t.Fatalf("unexpected error: %v", err)
131+
}
132+
if len(result) == 0 {
133+
return
134+
}
135+
num := uint64(result[0])
136+
data := result[1:]
137+
date, err := parseBinaryDateTime(num, data, time.UTC)
138+
if err != nil {
139+
t.Fatalf("unexpected error: %v", err)
140+
}
141+
142+
if !strings.EqualFold(date.String(), tt.expected) {
143+
t.Errorf("expected %v, got %v", tt.expected, result)
144+
}
145+
})
146+
}
147+
}

0 commit comments

Comments
 (0)