@@ -338,17 +338,28 @@ type timeTest struct {
338
338
t time.Time
339
339
}
340
340
341
+ func (t timeTest ) genQuery (dbtype string , binaryProtocol bool ) string {
342
+ var inner string
343
+ if binaryProtocol {
344
+ inner = "?"
345
+ } else {
346
+ inner = `"%s"`
347
+ }
348
+ if len (dbtype ) >= 9 && dbtype [:9 ] == "TIMESTAMP" {
349
+ return `SELECT TIMESTAMPADD(SECOND,0,CAST(` + inner + ` AS DATETIME` + dbtype [9 :] + `))`
350
+ }
351
+ return `SELECT CAST(` + inner + ` AS ` + dbtype + `)`
352
+ }
353
+
341
354
func (t timeTest ) run (dbt * DBTest , dbtype , tlayout string , binaryProtocol bool ) {
342
- const queryBin = `SELECT CAST(? AS %[2]s)`
343
- const queryTxt = `SELECT CAST("%[1]s" AS %[2]s)`
344
355
var rows * sql.Rows
345
356
var protocol string
346
- if binaryProtocol {
357
+ if query := t . genQuery ( dbtype , binaryProtocol ); binaryProtocol {
347
358
protocol = "binary"
348
- rows = dbt .mustQuery (fmt . Sprintf ( queryBin , t . s , dbtype ) , t .t )
359
+ rows = dbt .mustQuery (query , t .t )
349
360
} else {
350
361
protocol = "text"
351
- rows = dbt .mustQuery (fmt .Sprintf (queryTxt , t .s , dbtype ))
362
+ rows = dbt .mustQuery (fmt .Sprintf (query , t .s ))
352
363
}
353
364
defer rows .Close ()
354
365
var err error
@@ -396,16 +407,17 @@ func (t timeTest) run(dbt *DBTest, dbtype, tlayout string, binaryProtocol bool)
396
407
}
397
408
398
409
func TestDateTime (t * testing.T ) {
399
- afterTime0 := func (d string ) time.Time {
410
+ afterTime := func (t time. Time , d string ) time.Time {
400
411
dur , err := time .ParseDuration (d )
401
412
if err != nil {
402
413
panic (err )
403
414
}
404
- return time. Time {} .Add (dur )
415
+ return t .Add (dur )
405
416
}
406
417
// NOTE: MySQL rounds DATETIME(x) up - but that's not included in the tests
407
418
format := "2006-01-02 15:04:05.999999"
408
419
t0 := time.Time {}
420
+ ts0 := time .Date (1970 , 1 , 1 , 0 , 0 , 0 , 0 , time .UTC )
409
421
tstr0 := "0000-00-00 00:00:00.000000"
410
422
testcases := []timeTests {
411
423
{"DATE" , format [:10 ], []timeTest {
@@ -425,34 +437,61 @@ func TestDateTime(t *testing.T) {
425
437
{t : t0 , s : tstr0 },
426
438
}},
427
439
{"TIME" , format [11 :19 ], []timeTest {
428
- {t : afterTime0 ( "12345s" )},
429
- {t : afterTime0 ( "-12345s" )},
440
+ {t : afterTime ( t0 , "12345s" )},
441
+ {t : afterTime ( t0 , "-12345s" )},
430
442
{t : t0 , s : tstr0 [11 :19 ]},
431
443
}},
432
444
{"TIME(1)" , format [11 :21 ], []timeTest {
433
- {t : afterTime0 ( "12345600ms" )},
434
- {t : afterTime0 ( "-12345600ms" )},
445
+ {t : afterTime ( t0 , "12345600ms" )},
446
+ {t : afterTime ( t0 , "-12345600ms" )},
435
447
{t : t0 , s : tstr0 [11 :21 ]},
436
448
}},
437
449
{"TIME(6)" , format [11 :], []timeTest {
438
- {t : afterTime0 ( "1234567890123000ns" )},
439
- {t : afterTime0 ( "-1234567890123000ns" )},
450
+ {t : afterTime ( t0 , "1234567890123000ns" )},
451
+ {t : afterTime ( t0 , "-1234567890123000ns" )},
440
452
{t : t0 , s : tstr0 [11 :]},
441
453
}},
454
+ {"TIMESTAMP" , format [:19 ], []timeTest {
455
+ {t : afterTime (ts0 , "12345s" )},
456
+ {t : ts0 , s : "1970-01-01 00:00:00" },
457
+ }},
458
+ {"TIMESTAMP(1)" , format [:21 ], []timeTest {
459
+ {t : afterTime (ts0 , "12345600ms" )},
460
+ {t : ts0 , s : "1970-01-01 00:00:00.0" },
461
+ }},
462
+ {"TIMESTAMP(6)" , format , []timeTest {
463
+ {t : afterTime (ts0 , "1234567890123000ns" )},
464
+ {t : ts0 , s : "1970-01-01 00:00:00.000000" },
465
+ }},
442
466
}
443
467
dsns := map [string ]bool {
444
468
dsn + "&parseTime=true" : true ,
445
469
dsn + "&sql_mode=ALLOW_INVALID_DATES&parseTime=true" : true ,
446
470
dsn + "&parseTime=false" : false ,
447
471
dsn + "&sql_mode=ALLOW_INVALID_DATES&parseTime=false" : false ,
448
472
}
473
+ var withFrac bool
474
+ if db , err := sql .Open ("mysql" , dsn ); err != nil {
475
+ t .Fatal (err )
476
+ } else {
477
+ rows , err := db .Query (`SELECT CAST("00:00:00.123" AS TIME(3)) = "00:00:00.123"` )
478
+ if err == nil {
479
+ withFrac = true
480
+ rows .Close ()
481
+ }
482
+ db .Close ()
483
+ }
449
484
for testdsn , parseTime := range dsns {
450
485
var _ = parseTime
451
486
runTests (t , testdsn , func (dbt * DBTest ) {
452
487
for _ , setups := range testcases {
488
+ if t := setups .dbtype ; ! withFrac && t [len (t )- 1 :] == ")" {
489
+ // skip fractional tests if unsupported by DB
490
+ continue
491
+ }
453
492
for _ , setup := range setups .tests {
454
493
if setup .s == "" {
455
- // fill time string where Go can reliable produce it
494
+ // fill time string whereever Go can reliable produce it
456
495
setup .s = setup .t .Format (setups .tlayout )
457
496
}
458
497
setup .run (dbt , setups .dbtype , setups .tlayout , true )
@@ -1053,9 +1092,8 @@ func TestTimezoneConversion(t *testing.T) {
1053
1092
dbt .mustExec ("CREATE TABLE test (ts TIMESTAMP)" )
1054
1093
1055
1094
// Insert local time into database (should be converted)
1056
- utc , _ := time .LoadLocation ("UTC" )
1057
1095
usCentral , _ := time .LoadLocation ("US/Central" )
1058
- reftime := time .Date (2014 , 05 , 30 , 18 , 03 , 17 , 0 , utc ).In (usCentral )
1096
+ reftime := time .Date (2014 , 05 , 30 , 18 , 03 , 17 , 0 , time . UTC ).In (usCentral )
1059
1097
dbt .mustExec ("INSERT INTO test VALUE (?)" , reftime )
1060
1098
1061
1099
// Retrieve time from DB
0 commit comments