Skip to content

Commit 4fa0e7c

Browse files
committed
add new layout, rm type check on time conv, fix range
1 parent e57ca0f commit 4fa0e7c

File tree

1 file changed

+29
-26
lines changed

1 file changed

+29
-26
lines changed

sql/types/datetime.go

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,16 @@ var (
5252

5353
datetimeTypeMaxDate = time.Date(9999, 12, 31, 0, 0, 0, 0, time.UTC)
5454

55+
// datetimeTypeMinDate is the minimum representable Date value, MYSQL: 1000-01-01 00:00:00.000000 (microseconds)
5556
datetimeTypeMinDate = time.Date(1000, 1, 1, 0, 0, 0, 0, time.UTC)
5657

58+
// The MAX and MIN are extrapolated from commit ff05628a530 in the MySQL source code from my_time.cc
59+
// datetimeMaxTime is the maximum representable time value, MYSQL: 9999-12-31 23:59:59.999999 (microseconds)
60+
datetimeMaxTime = time.Date(9999, 12, 31, 23, 59, 59, 999999000, time.UTC)
61+
62+
// datetimeMinTime is the minimum representable time value, MYSQL: 0000-01-01 00:00:00.000000 (microseconds)
63+
datetimeMinTime = time.Date(0000, 0, 0, 0, 0, 0, 0, time.UTC)
64+
5765
DateOnlyLayouts = []string{
5866
"20060102",
5967
"2006-1-2",
@@ -74,8 +82,9 @@ var (
7482
"2006-01-02 15:04:",
7583
"2006-01-02 15:04:.",
7684
"2006-01-02 15:04:05.",
77-
"2006-01-02 15:04:05.999999",
78-
"2006-1-2 15:4:5.999999",
85+
"2006-01-02 15:04:05.999999999",
86+
"2006-1-2 15:4:5.999999999",
87+
"2006-1-2:15:4:5.999999999",
7988
"2006-01-02T15:04:05",
8089
"20060102150405",
8190
"2006-01-02 15:04:05.999999999 -0700 MST", // represents standard Time.time.UTC()
@@ -202,26 +211,7 @@ func ConvertToTime(ctx context.Context, v interface{}, t datetimeType) (time.Tim
202211
return zeroTime, nil
203212
}
204213

205-
// Round the date to the precision of this type
206-
truncationDuration := time.Second
207-
truncationDuration /= time.Duration(precisionConversion[t.precision])
208-
res = res.Round(truncationDuration)
209-
210-
switch t.baseType {
211-
case sqltypes.Date:
212-
if validated := ValidateDate(res); validated == nil {
213-
return time.Time{}, ErrConvertingToTimeOutOfRange.New(res.Format(sql.DateLayout), t.String())
214-
}
215-
case sqltypes.Datetime:
216-
if validated := ValidateDatetime(res); validated == nil {
217-
return time.Time{}, ErrConvertingToTimeOutOfRange.New(res.Format(sql.TimestampDatetimeLayout), t.String())
218-
}
219-
case sqltypes.Timestamp:
220-
if validated := ValidateTimestamp(res); validated == nil {
221-
return time.Time{}, ErrConvertingToTimeOutOfRange.New(res.Format(sql.TimestampDatetimeLayout), t.String())
222-
}
223-
}
224-
return res, nil
214+
return res.Round(time.Microsecond), nil
225215
}
226216

227217
// ConvertWithoutRangeCheck converts the parameter to time.Time without checking the range.
@@ -341,8 +331,8 @@ func (t datetimeType) ConvertWithoutRangeCheck(ctx context.Context, v interface{
341331
}
342332

343333
func parseDatetime(value string) (time.Time, bool) {
344-
for _, fmt := range TimestampDatetimeLayouts {
345-
if t, err := time.Parse(fmt, value); err == nil {
334+
for _, layout := range TimestampDatetimeLayouts {
335+
if t, err := time.Parse(layout, value); err == nil {
346336
return t.UTC(), true
347337
}
348338
}
@@ -473,9 +463,20 @@ func (t datetimeType) MinimumTime() time.Time {
473463
return datetimeTypeMinDatetime
474464
}
475465

476-
// validateDatetime receives a time and returns either that time or nil if it's
466+
// ValidateTime receives a time and returns either that time or nil if it's
477467
// not a valid time.
468+
func ValidateTime(t time.Time) interface{} {
469+
if t.Before(datetimeMinTime) || t.After(datetimeMaxTime) {
470+
return nil
471+
}
472+
473+
return t
474+
}
475+
476+
// ValidateDatetime receives a time and returns either that time or nil if it's
477+
// not a valid datetime.
478478
func ValidateDatetime(t time.Time) interface{} {
479+
t = t.Round(time.Microsecond)
479480
if t.Before(datetimeTypeMinDatetime) || t.After(datetimeTypeMaxDatetime) {
480481
return nil
481482
}
@@ -485,6 +486,7 @@ func ValidateDatetime(t time.Time) interface{} {
485486
// ValidateTimestamp receives a time and returns either that time or nil if it's
486487
// not a valid timestamp.
487488
func ValidateTimestamp(t time.Time) interface{} {
489+
t = t.Round(time.Microsecond)
488490
if t.Before(datetimeTypeMinTimestamp) || t.After(datetimeTypeMaxTimestamp) {
489491
return nil
490492
}
@@ -494,7 +496,8 @@ func ValidateTimestamp(t time.Time) interface{} {
494496
// validateDate receives a time and returns either that time or nil if it's
495497
// not a valid date.
496498
func ValidateDate(t time.Time) interface{} {
497-
if t.Before(datetimeTypeMinDatetime) || t.After(datetimeTypeMaxDate) {
499+
t = t.Round(time.Microsecond)
500+
if t.Before(datetimeTypeMinDate) || t.After(datetimeTypeMaxDate) {
498501
return nil
499502
}
500503
return t

0 commit comments

Comments
 (0)