Skip to content
This repository was archived by the owner on Jan 28, 2021. It is now read-only.

Commit 8796d13

Browse files
authored
Merge pull request #480 from jfontan/improvement/support-more-timestamp-layouts
sql: support more timestamp formats
2 parents 4095f3d + 7f1104a commit 8796d13

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

engine_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,18 @@ var queries = []struct {
9292
"SELECT DAYOFYEAR('2007-12-11 20:21:22') FROM mytable",
9393
[]sql.Row{{int32(345)}, {int32(345)}, {int32(345)}},
9494
},
95+
{
96+
"SELECT SECOND('2007-12-11T20:21:22Z') FROM mytable",
97+
[]sql.Row{{int32(22)}, {int32(22)}, {int32(22)}},
98+
},
99+
{
100+
"SELECT DAYOFYEAR('2007-12-11') FROM mytable",
101+
[]sql.Row{{int32(345)}, {int32(345)}, {int32(345)}},
102+
},
103+
{
104+
"SELECT DAYOFYEAR('20071211') FROM mytable",
105+
[]sql.Row{{int32(345)}, {int32(345)}, {int32(345)}},
106+
},
95107
{
96108
"SELECT i FROM mytable WHERE i BETWEEN 1 AND 2",
97109
[]sql.Row{{int64(1)}, {int64(2)}},

sql/type.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,18 @@ func (t timestampT) Type() query.Type {
367367
// using the format of Go "time" package.
368368
const TimestampLayout = "2006-01-02 15:04:05"
369369

370+
// TimestampLayouts hold extra timestamps allowed for parsing. It does
371+
// not have all the layouts supported by mysql. Missing are two digit year
372+
// versions of common cases and dates that use non common separators.
373+
//
374+
// https://github.com/MariaDB/server/blob/mysql-5.5.36/sql-common/my_time.c#L124
375+
var TimestampLayouts = []string{
376+
"2006-01-02",
377+
time.RFC3339,
378+
"20060102150405",
379+
"20060102",
380+
}
381+
370382
// SQL implements Type interface.
371383
func (t timestampT) SQL(v interface{}) sqltypes.Value {
372384
time := MustConvert(t, v).(time.Time)
@@ -384,7 +396,18 @@ func (t timestampT) Convert(v interface{}) (interface{}, error) {
384396
case string:
385397
t, err := time.Parse(TimestampLayout, value)
386398
if err != nil {
387-
return nil, ErrConvertingToTime.Wrap(err, v)
399+
failed := true
400+
for _, fmt := range TimestampLayouts {
401+
if t2, err2 := time.Parse(fmt, value); err2 == nil {
402+
t = t2
403+
failed = false
404+
break
405+
}
406+
}
407+
408+
if failed {
409+
return nil, ErrConvertingToTime.Wrap(err, v)
410+
}
388411
}
389412
return t.UTC(), nil
390413
default:

sql/type_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,46 @@ func TestTimestamp(t *testing.T) {
9898
gt(t, Timestamp, after, now)
9999
}
100100

101+
func TestExtraTimestamps(t *testing.T) {
102+
tests := []struct {
103+
date string
104+
expected string
105+
}{
106+
{
107+
date: "2018-10-18T05:22:25Z",
108+
expected: "2018-10-18 05:22:25",
109+
},
110+
{
111+
date: "2018-10-18T05:22:25+07:00",
112+
expected: "2018-10-17 22:22:25",
113+
},
114+
{
115+
date: "20181018052225",
116+
expected: "2018-10-18 05:22:25",
117+
},
118+
{
119+
date: "20181018",
120+
expected: "2018-10-18 00:00:00",
121+
},
122+
{
123+
date: "2018-10-18",
124+
expected: "2018-10-18 00:00:00",
125+
},
126+
}
127+
128+
for _, c := range tests {
129+
t.Run(c.date, func(t *testing.T) {
130+
require := require.New(t)
131+
132+
p, err := Timestamp.Convert(c.date)
133+
require.NoError(err)
134+
135+
str := string([]byte(p.(time.Time).Format(TimestampLayout)))
136+
require.Equal(c.expected, str)
137+
})
138+
}
139+
}
140+
101141
func TestDate(t *testing.T) {
102142
require := require.New(t)
103143
now := time.Now().UTC()

0 commit comments

Comments
 (0)