Skip to content

Commit

Permalink
types: Fix potential timezone related bugs caused by gotime.Local (p…
Browse files Browse the repository at this point in the history
  • Loading branch information
Rustin170506 authored and XiaTianliang committed Dec 21, 2019
1 parent 31b765b commit 87c2495
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 25 deletions.
11 changes: 9 additions & 2 deletions server/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/types/json"
"github.com/pingcap/tidb/util/chunk"
"github.com/pingcap/tidb/util/mock"
"github.com/pingcap/tidb/util/testleak"
)

Expand Down Expand Up @@ -163,15 +164,21 @@ func (s *testUtilSuite) TestDumpTextValue(c *C) {

var d types.Datum

time, err := types.ParseTime(nil, "2017-01-05 23:59:59.575601", mysql.TypeDatetime, 0)
sc := mock.NewContext().GetSessionVars().StmtCtx
sc.IgnoreZeroInDate = true
losAngelesTz, err := time.LoadLocation("America/Los_Angeles")
c.Assert(err, IsNil)
sc.TimeZone = losAngelesTz

time, err := types.ParseTime(sc, "2017-01-05 23:59:59.575601", mysql.TypeDatetime, 0)
c.Assert(err, IsNil)
d.SetMysqlTime(time)
columns[0].Type = mysql.TypeDatetime
bs, err = dumpTextRow(nil, columns, chunk.MutRowFromDatums([]types.Datum{d}).ToRow())
c.Assert(err, IsNil)
c.Assert(mustDecodeStr(c, bs), Equals, "2017-01-06 00:00:00")

duration, err := types.ParseDuration(nil, "11:30:45", 0)
duration, err := types.ParseDuration(sc, "11:30:45", 0)
c.Assert(err, IsNil)
d.SetMysqlDuration(duration)
columns[0].Type = mysql.TypeDuration
Expand Down
7 changes: 3 additions & 4 deletions types/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,15 @@ func (s *testTypeConvertSuite) TestConvertType(c *C) {
vv, err := Convert(v, ft)
c.Assert(err, IsNil)
c.Assert(vv.(Duration).String(), Equals, "10:11:12.1")

vd, err := ParseTime(nil, "2010-10-10 10:11:11.12345", mysql.TypeDatetime, 2)
sc := &stmtctx.StatementContext{TimeZone: time.UTC}
vd, err := ParseTime(sc, "2010-10-10 10:11:11.12345", mysql.TypeDatetime, 2)
c.Assert(vd.String(), Equals, "2010-10-10 10:11:11.12")
c.Assert(err, IsNil)
v, err = Convert(vd, ft)
c.Assert(err, IsNil)
c.Assert(v.(Duration).String(), Equals, "10:11:11.1")

vt, err := ParseTime(&stmtctx.StatementContext{TimeZone: time.UTC}, "2010-10-10 10:11:11.12345", mysql.TypeTimestamp, 2)
vt, err := ParseTime(sc, "2010-10-10 10:11:11.12345", mysql.TypeTimestamp, 2)
c.Assert(vt.String(), Equals, "2010-10-10 10:11:11.12")
c.Assert(err, IsNil)
v, err = Convert(vt, ft)
Expand Down Expand Up @@ -249,7 +249,6 @@ func (s *testTypeConvertSuite) TestConvertType(c *C) {

// Test Datum.ToDecimal with bad number.
d := NewDatum("hello")
sc := new(stmtctx.StatementContext)
_, err = d.ToDecimal(sc)
c.Assert(terror.ErrorEqual(err, ErrBadNumber), IsTrue, Commentf("err %v", err))

Expand Down
2 changes: 1 addition & 1 deletion types/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -824,7 +824,7 @@ func parseDatetime(sc *stmtctx.StatementContext, str string, fsp int8, isFloat b
tmp := FromDate(year, month, day, hour, minute, second, microsecond)
if overflow {
// Convert to Go time and add 1 second, to handle input like 2017-01-05 08:40:59.575601
t1, err := tmp.GoTime(gotime.Local)
t1, err := tmp.GoTime(sc.TimeZone)
if err != nil {
return ZeroDatetime, errors.Trace(err)
}
Expand Down
41 changes: 24 additions & 17 deletions types/time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ func (s *testTimeSuite) TestCodec(c *C) {
}

for _, test := range tbl {
t, err := types.ParseTime(nil, test, mysql.TypeDatetime, types.MaxFsp)
t, err := types.ParseTime(sc, test, mysql.TypeDatetime, types.MaxFsp)
c.Assert(err, IsNil)

packed, _ = t.ToPackedUint()
Expand Down Expand Up @@ -582,6 +582,9 @@ func (s *testTimeSuite) TestParseTimeFromNum(c *C) {
func (s *testTimeSuite) TestToNumber(c *C) {
sc := mock.NewContext().GetSessionVars().StmtCtx
sc.IgnoreZeroInDate = true
losAngelesTz, err := time.LoadLocation("America/Los_Angeles")
c.Assert(err, IsNil)
sc.TimeZone = losAngelesTz
defer testleak.AfterTest(c)()
tblDateTime := []struct {
Input string
Expand All @@ -600,7 +603,7 @@ func (s *testTimeSuite) TestToNumber(c *C) {
}

for _, test := range tblDateTime {
t, err := types.ParseTime(nil, test.Input, mysql.TypeDatetime, test.Fsp)
t, err := types.ParseTime(sc, test.Input, mysql.TypeDatetime, test.Fsp)
c.Assert(err, IsNil)
c.Assert(t.ToNumber().String(), Equals, test.Expect)
}
Expand All @@ -623,7 +626,7 @@ func (s *testTimeSuite) TestToNumber(c *C) {
}

for _, test := range tblDate {
t, err := types.ParseTime(nil, test.Input, mysql.TypeDate, 0)
t, err := types.ParseTime(sc, test.Input, mysql.TypeDate, 0)
c.Assert(err, IsNil)
c.Assert(t.ToNumber().String(), Equals, test.Expect)
}
Expand Down Expand Up @@ -721,7 +724,8 @@ func (s *testTimeSuite) TestRoundFrac(c *C) {
c.Assert(nv.String(), Equals, t.Except)
}
// test different time zone
losAngelesTz, _ := time.LoadLocation("America/Los_Angeles")
losAngelesTz, err := time.LoadLocation("America/Los_Angeles")
c.Assert(err, IsNil)
sc.TimeZone = losAngelesTz
tbl = []struct {
Input string
Expand Down Expand Up @@ -783,6 +787,10 @@ func (s *testTimeSuite) TestRoundFrac(c *C) {
}

func (s *testTimeSuite) TestConvert(c *C) {
sc := mock.NewContext().GetSessionVars().StmtCtx
sc.IgnoreZeroInDate = true
losAngelesTz, _ := time.LoadLocation("America/Los_Angeles")
sc.TimeZone = losAngelesTz
defer testleak.AfterTest(c)()
tbl := []struct {
Input string
Expand All @@ -799,7 +807,7 @@ func (s *testTimeSuite) TestConvert(c *C) {
}

for _, t := range tbl {
v, err := types.ParseTime(nil, t.Input, mysql.TypeDatetime, t.Fsp)
v, err := types.ParseTime(sc, t.Input, mysql.TypeDatetime, t.Fsp)
c.Assert(err, IsNil)
nv, err := v.ConvertToDuration()
c.Assert(err, IsNil)
Expand All @@ -815,23 +823,22 @@ func (s *testTimeSuite) TestConvert(c *C) {
{"11:30:45.123456", 0},
{"1 11:30:45.999999", 0},
}

sc := mock.NewContext().GetSessionVars().StmtCtx
// test different time zone.
sc.TimeZone = time.UTC
for _, t := range tblDuration {
v, err := types.ParseDuration(sc, t.Input, t.Fsp)
c.Assert(err, IsNil)
year, month, day := time.Now().In(time.UTC).Date()
n := time.Date(year, month, day, 0, 0, 0, 0, time.UTC)
year, month, day := time.Now().In(sc.TimeZone).Date()
n := time.Date(year, month, day, 0, 0, 0, 0, sc.TimeZone)
t, err := v.ConvertToTime(sc, mysql.TypeDatetime)
c.Assert(err, IsNil)
// TODO: Consider time_zone variable.
t1, _ := t.Time.GoTime(time.UTC)
t1, _ := t.Time.GoTime(sc.TimeZone)
c.Assert(t1.Sub(n), Equals, v.Duration)
}
}

func (s *testTimeSuite) TestCompare(c *C) {
sc := &stmtctx.StatementContext{TimeZone: time.UTC}
defer testleak.AfterTest(c)()
tbl := []struct {
Arg1 string
Expand All @@ -846,15 +853,15 @@ func (s *testTimeSuite) TestCompare(c *C) {
}

for _, t := range tbl {
v1, err := types.ParseTime(nil, t.Arg1, mysql.TypeDatetime, types.MaxFsp)
v1, err := types.ParseTime(sc, t.Arg1, mysql.TypeDatetime, types.MaxFsp)
c.Assert(err, IsNil)

ret, err := v1.CompareString(nil, t.Arg2)
c.Assert(err, IsNil)
c.Assert(ret, Equals, t.Ret)
}

v1, err := types.ParseTime(nil, "2011-10-10 11:11:11", mysql.TypeDatetime, types.MaxFsp)
v1, err := types.ParseTime(sc, "2011-10-10 11:11:11", mysql.TypeDatetime, types.MaxFsp)
c.Assert(err, IsNil)
res, err := v1.CompareString(nil, "Test should error")
c.Assert(err, NotNil)
Expand Down Expand Up @@ -1015,11 +1022,11 @@ func (s *testTimeSuite) TestTimeAdd(c *C) {
TimeZone: time.UTC,
}
for _, t := range tbl {
v1, err := types.ParseTime(nil, t.Arg1, mysql.TypeDatetime, types.MaxFsp)
v1, err := types.ParseTime(sc, t.Arg1, mysql.TypeDatetime, types.MaxFsp)
c.Assert(err, IsNil)
dur, err := types.ParseDuration(sc, t.Arg2, types.MaxFsp)
c.Assert(err, IsNil)
result, err := types.ParseTime(nil, t.Ret, mysql.TypeDatetime, types.MaxFsp)
result, err := types.ParseTime(sc, t.Ret, mysql.TypeDatetime, types.MaxFsp)
c.Assert(err, IsNil)
v2, err := v1.Add(sc, dur)
c.Assert(err, IsNil)
Expand Down Expand Up @@ -1652,9 +1659,9 @@ func (s *testTimeSuite) TestTimeSub(c *C) {
TimeZone: time.UTC,
}
for _, t := range tbl {
v1, err := types.ParseTime(nil, t.Arg1, mysql.TypeDatetime, types.MaxFsp)
v1, err := types.ParseTime(sc, t.Arg1, mysql.TypeDatetime, types.MaxFsp)
c.Assert(err, IsNil)
v2, err := types.ParseTime(nil, t.Arg2, mysql.TypeDatetime, types.MaxFsp)
v2, err := types.ParseTime(sc, t.Arg2, mysql.TypeDatetime, types.MaxFsp)
c.Assert(err, IsNil)
dur, err := types.ParseDuration(sc, t.Ret, types.MaxFsp)
c.Assert(err, IsNil)
Expand Down
3 changes: 2 additions & 1 deletion util/codec/codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,8 @@ func (s *testCodecSuite) TestBytes(c *C) {
}

func parseTime(c *C, s string) types.Time {
m, err := types.ParseTime(nil, s, mysql.TypeDatetime, types.DefaultFsp)
sc := &stmtctx.StatementContext{TimeZone: time.UTC}
m, err := types.ParseTime(sc, s, mysql.TypeDatetime, types.DefaultFsp)
c.Assert(err, IsNil)
return m
}
Expand Down

0 comments on commit 87c2495

Please sign in to comment.