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" ,
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
343333func 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.
478478func 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.
487488func 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.
496498func 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