@@ -17,7 +17,6 @@ package types
1717import (
1818 "context"
1919 "fmt"
20- "math"
2120 "reflect"
2221 "time"
2322
@@ -39,17 +38,21 @@ var (
3938
4039 ErrConvertingToTimeOutOfRange = errors .NewKind ("value %q is outside of %v range" )
4140
42- // datetimeTypeMaxDatetime is the maximum representable Datetime/Date value.
43- datetimeTypeMaxDatetime = time .Date (9999 , 12 , 31 , 23 , 59 , 59 , 999999000 , time .UTC )
41+ // datetimeTypeMaxDatetime is the maximum representable Datetime/Date value. MYSQL: 9999-12-31 23:59:59.499999 (microseconds)
42+ datetimeTypeMaxDatetime = time .Date (9999 , 12 , 31 , 23 , 59 , 59 , 499999000 , time .UTC )
4443
45- // datetimeTypeMinDatetime is the minimum representable Datetime/Date value.
46- datetimeTypeMinDatetime = time .Date (0 , 1 , 1 , 0 , 0 , 0 , 0 , time .UTC )
44+ // datetimeTypeMinDatetime is the minimum representable Datetime/Date value. MYSQL: 1000-01-01 00:00:00.000000 (microseconds)
45+ datetimeTypeMinDatetime = time .Date (1000 , 1 , 1 , 0 , 0 , 0 , 0 , time .UTC )
4746
48- // datetimeTypeMaxTimestamp is the maximum representable Timestamp value, which is the maximum 32-bit integer as a Unix time.
49- datetimeTypeMaxTimestamp = time .Unix ( math . MaxInt32 , 999999000 )
47+ // datetimeTypeMaxTimestamp is the maximum representable Timestamp value, MYSQL: 2038-01-19 03:14:07.999999 (microseconds)
48+ datetimeTypeMaxTimestamp = time .Date ( 2038 , 1 , 19 , 3 , 14 , 7 , 999999000 , time . UTC )
5049
51- // datetimeTypeMinTimestamp is the minimum representable Timestamp value, which is one second past the epoch.
52- datetimeTypeMinTimestamp = time .Unix (1 , 0 )
50+ // datetimeTypeMinTimestamp is the minimum representable Timestamp value, MYSQL: 1970-01-01 00:00:01.000000 (microseconds)
51+ datetimeTypeMinTimestamp = time .Date (1970 , 1 , 1 , 0 , 0 , 1 , 0 , time .UTC )
52+
53+ datetimeTypeMaxDate = time .Date (9999 , 12 , 31 , 0 , 0 , 0 , 0 , time .UTC )
54+
55+ datetimeTypeMinDate = time .Date (1000 , 1 , 1 , 0 , 0 , 0 , 0 , time .UTC )
5356
5457 DateOnlyLayouts = []string {
5558 "20060102" ,
@@ -206,15 +209,15 @@ func ConvertToTime(ctx context.Context, v interface{}, t datetimeType) (time.Tim
206209
207210 switch t .baseType {
208211 case sqltypes .Date :
209- if res . Year () < 0 || res . Year () > 9999 {
212+ if validated := ValidateDate ( res ); validated == nil {
210213 return time.Time {}, ErrConvertingToTimeOutOfRange .New (res .Format (sql .DateLayout ), t .String ())
211214 }
212215 case sqltypes .Datetime :
213- if res . Year () < 0 || res . Year () > 9999 {
216+ if validated := ValidateDatetime ( res ); validated == nil {
214217 return time.Time {}, ErrConvertingToTimeOutOfRange .New (res .Format (sql .TimestampDatetimeLayout ), t .String ())
215218 }
216219 case sqltypes .Timestamp :
217- if res . Before ( datetimeTypeMinTimestamp ) || res . After ( datetimeTypeMaxTimestamp ) {
220+ if validated := ValidateTimestamp ( res ); validated == nil {
218221 return time.Time {}, ErrConvertingToTimeOutOfRange .New (res .Format (sql .TimestampDatetimeLayout ), t .String ())
219222 }
220223 }
@@ -470,10 +473,28 @@ func (t datetimeType) MinimumTime() time.Time {
470473 return datetimeTypeMinDatetime
471474}
472475
473- // ValidateTime receives a time and returns either that time or nil if it's
476+ // validateDatetime receives a time and returns either that time or nil if it's
474477// not a valid time.
475- func ValidateTime (t time.Time ) interface {} {
476- if t .After (time .Date (9999 , time .December , 31 , 23 , 59 , 59 , 999999999 , time .UTC )) {
478+ func ValidateDatetime (t time.Time ) interface {} {
479+ if t .Before (datetimeTypeMinDatetime ) || t .After (datetimeTypeMaxDatetime ) {
480+ return nil
481+ }
482+ return t
483+ }
484+
485+ // ValidateTimestamp receives a time and returns either that time or nil if it's
486+ // not a valid timestamp.
487+ func ValidateTimestamp (t time.Time ) interface {} {
488+ if t .Before (datetimeTypeMinTimestamp ) || t .After (datetimeTypeMaxTimestamp ) {
489+ return nil
490+ }
491+ return t
492+ }
493+
494+ // validateDate receives a time and returns either that time or nil if it's
495+ // not a valid date.
496+ func ValidateDate (t time.Time ) interface {} {
497+ if t .Before (datetimeTypeMinDatetime ) || t .After (datetimeTypeMaxDate ) {
477498 return nil
478499 }
479500 return t
0 commit comments