Skip to content

Commit

Permalink
BREAK: prefer UTC over Local tz for deserialization
Browse files Browse the repository at this point in the history
  • Loading branch information
jpalawaga committed Nov 1, 2021
1 parent 00d27f8 commit 8e9dfd9
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 21 deletions.
12 changes: 8 additions & 4 deletions column.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ func (c *BaseColumn) Value(buf []byte) (driver.Value, error) {
if len(buf) > 0 {
p = unsafe.Pointer(&buf[0])
}
loc := time.UTC
if drv.Loc != nil {
loc = drv.Loc
}
switch c.CType {
case api.SQL_C_BIT:
return buf[0] != 0, nil
Expand All @@ -152,7 +156,7 @@ func (c *BaseColumn) Value(buf []byte) (driver.Value, error) {
t := (*api.SQL_TIMESTAMP_STRUCT)(p)
r := time.Date(int(t.Year), time.Month(t.Month), int(t.Day),
int(t.Hour), int(t.Minute), int(t.Second), int(t.Fraction),
time.Local)
loc)
return r, nil
case api.SQL_C_GUID:
t := (*api.SQLGUID)(p)
Expand All @@ -169,19 +173,19 @@ func (c *BaseColumn) Value(buf []byte) (driver.Value, error) {
case api.SQL_C_DATE:
t := (*api.SQL_DATE_STRUCT)(p)
r := time.Date(int(t.Year), time.Month(t.Month), int(t.Day),
0, 0, 0, 0, time.Local)
0, 0, 0, 0, loc)
return r, nil
case api.SQL_C_TIME:
t := (*api.SQL_TIME_STRUCT)(p)
r := time.Date(1, time.January, 1,
int(t.Hour), int(t.Minute), int(t.Second), 0, time.Local)
int(t.Hour), int(t.Minute), int(t.Second), 0, loc)
return r, nil
case api.SQL_C_BINARY:
if c.SQLType == api.SQL_SS_TIME2 {
t := (*api.SQL_SS_TIME2_STRUCT)(p)
r := time.Date(1, time.January, 1,
int(t.Hour), int(t.Minute), int(t.Second), int(t.Fraction),
time.Local)
loc)
return r, nil
}
return buf, nil
Expand Down
1 change: 1 addition & 0 deletions driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Driver struct {
Stats
h api.SQLHENV // environment handle
initErr error
Loc *time.Location
}

func initDriver() error {
Expand Down
8 changes: 4 additions & 4 deletions foxpro_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func TestFoxPro(t *testing.T) {
num_2_0: sql.NullFloat64{Float64: 1, Valid: true},
num_20_0: 1232543,
num_6_3: 12.73,
date: time.Date(2012, 5, 19, 0, 0, 0, 0, time.Local),
date: time.Date(2012, 5, 19, 0, 0, 0, 0, time.UTC),
float_2_0: 23,
float_20_0: 12345678901234560,
float_6_3: 12.345,
Expand All @@ -62,7 +62,7 @@ func TestFoxPro(t *testing.T) {
num_2_0: sql.NullFloat64{Float64: 23, Valid: true},
num_20_0: 4564568,
num_6_3: 2,
date: time.Date(2012, 5, 20, 0, 0, 0, 0, time.Local),
date: time.Date(2012, 5, 20, 0, 0, 0, 0, time.UTC),
float_2_0: 1,
float_20_0: 234,
float_6_3: 0.123,
Expand All @@ -74,7 +74,7 @@ func TestFoxPro(t *testing.T) {
num_2_0: sql.NullFloat64{Float64: 4, Valid: true},
num_20_0: 1234567890123456000,
num_6_3: 99.99,
date: time.Date(2012, 5, 21, 0, 0, 0, 0, time.Local),
date: time.Date(2012, 5, 21, 0, 0, 0, 0, time.UTC),
float_2_0: 23,
float_20_0: 457768,
float_6_3: 99,
Expand All @@ -86,7 +86,7 @@ func TestFoxPro(t *testing.T) {
num_2_0: sql.NullFloat64{Float64: 0, Valid: false},
num_20_0: 234456,
num_6_3: 0.123,
date: time.Date(2012, 5, 22, 0, 0, 0, 0, time.Local),
date: time.Date(2012, 5, 22, 0, 0, 0, 0, time.UTC),
float_2_0: 65,
float_20_0: 234,
float_6_3: 1,
Expand Down
24 changes: 12 additions & 12 deletions mssql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,15 +286,15 @@ func TestMSSQLCreateInsertDelete(t *testing.T) {
age: 5,
isGirl: true,
weight: 15.5,
dob: time.Date(2000, 5, 10, 11, 1, 1, 0, time.Local),
dob: time.Date(2000, 5, 10, 11, 1, 1, 0, time.UTC),
data: []byte{0x0, 0x0, 0xb, 0xad, 0xc0, 0xde},
canBeNull: sql.NullString{"aa", true},
},
"gopher": {
age: 3,
isGirl: false,
weight: 26.12,
dob: time.Date(2009, 5, 10, 11, 1, 1, 123e6, time.Local),
dob: time.Date(2009, 5, 10, 11, 1, 1, 123e6, time.UTC),
data: []byte{0x0},
canBeNull: sql.NullString{"bbb", true},
},
Expand All @@ -315,11 +315,11 @@ func TestMSSQLCreateInsertDelete(t *testing.T) {
t.Fatal(err)
}
}
_, err = s.Exec("chris", 25, 0, 50, time.Date(2015, 12, 25, 0, 0, 0, 0, time.Local), "ccc", nil)
_, err = s.Exec("chris", 25, 0, 50, time.Date(2015, 12, 25, 0, 0, 0, 0, time.UTC), "ccc", nil)
if err != nil {
t.Fatal(err)
}
_, err = s.Exec("null", 0, 0, 0, time.Date(2015, 12, 25, 1, 2, 3, 0, time.Local), nil, nil)
_, err = s.Exec("null", 0, 0, 0, time.Date(2015, 12, 25, 1, 2, 3, 0, time.UTC), nil, nil)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -621,10 +621,10 @@ var typeTests = []typeTest{
{"select cast(NULL as nvarchar(5))", match(nil)},

// datetime, smalldatetime
{"select cast('20151225' as datetime)", match(time.Date(2015, 12, 25, 0, 0, 0, 0, time.Local))},
{"select cast('2007-05-08 12:35:29.123' as datetime)", match(time.Date(2007, 5, 8, 12, 35, 29, 123e6, time.Local))},
{"select cast('20151225' as datetime)", match(time.Date(2015, 12, 25, 0, 0, 0, 0, time.UTC))},
{"select cast('2007-05-08 12:35:29.123' as datetime)", match(time.Date(2007, 5, 8, 12, 35, 29, 123e6, time.UTC))},
{"select cast(NULL as datetime)", match(nil)},
{"select cast('2007-05-08 12:35:29.123' as smalldatetime)", match(time.Date(2007, 5, 8, 12, 35, 0, 0, time.Local))},
{"select cast('2007-05-08 12:35:29.123' as smalldatetime)", match(time.Date(2007, 5, 8, 12, 35, 0, 0, time.UTC))},

// uniqueidentifier
{"select cast('0e984725-c51c-4bf4-9960-e1c80e27aba0' as uniqueidentifier)", match("0e984725-c51c-4bf4-9960-e1c80e27aba0")},
Expand Down Expand Up @@ -675,12 +675,12 @@ var typeMSSpecificTests = []typeTest{

var typeMSSQL2008Tests = []typeTest{
// datetime2
{"select cast('20151225' as datetime2)", match(time.Date(2015, 12, 25, 0, 0, 0, 0, time.Local))},
{"select cast('2007-05-08 12:35:29.1234567' as datetime2)", match(time.Date(2007, 5, 8, 12, 35, 29, 1234567e2, time.Local))},
{"select cast('20151225' as datetime2)", match(time.Date(2015, 12, 25, 0, 0, 0, 0, time.UTC))},
{"select cast('2007-05-08 12:35:29.1234567' as datetime2)", match(time.Date(2007, 5, 8, 12, 35, 29, 1234567e2, time.UTC))},
{"select cast(NULL as datetime2)", match(nil)},

// time(7)
{"select cast('12:35:29.1234567' as time(7))", match(time.Date(1, 1, 1, 12, 35, 29, 1234567e2, time.Local))},
{"select cast('12:35:29.1234567' as time(7))", match(time.Date(1, 1, 1, 12, 35, 29, 1234567e2, time.UTC))},
{"select cast(NULL as time(7))", match(nil)},
}

Expand Down Expand Up @@ -1079,7 +1079,7 @@ func TestMSSQLDatetime2Param(t *testing.T) {
db.Exec("drop table dbo.temp")
exec(t, db, "create table dbo.temp (dt datetime2)")

expect := time.Date(2007, 5, 8, 12, 35, 29, 1234567e2, time.Local)
expect := time.Date(2007, 5, 8, 12, 35, 29, 1234567e2, time.UTC)
_, err = db.Exec("insert into dbo.temp (dt) values (?)", expect)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -1257,7 +1257,7 @@ var paramTypeTests = []struct {
{"4001 large unicode string value", "ntext", strings.Repeat("\u0421", 4001)},
{"very large string value", "text", strings.Repeat("a", 10000)},
// datetime
{"datetime overflow", "datetime", time.Date(2013, 9, 9, 14, 07, 15, 123e6, time.Local)},
{"datetime overflow", "datetime", time.Date(2013, 9, 9, 14, 07, 15, 123e6, time.UTC)},
// binary blobs
{"small blob", "varbinary", make([]byte, 1)},
{"very large blob", "varbinary(max)", make([]byte, 100000)},
Expand Down
2 changes: 1 addition & 1 deletion mysql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func TestMYSQLTime(t *testing.T) {
exec(t, db, "create table temp(id int not null auto_increment primary key, time time)")
now := time.Now()
// SQL_TIME_STRUCT only supports hours, minutes and seconds
now = time.Date(1, time.January, 1, now.Hour(), now.Minute(), now.Second(), 0, time.Local)
now = time.Date(1, time.January, 1, now.Hour(), now.Minute(), now.Second(), 0, time.UTC)
_, err = db.Exec("insert into temp (time) values(?)", now)
if err != nil {
t.Fatal(err)
Expand Down

0 comments on commit 8e9dfd9

Please sign in to comment.