types: Fix potential timezone related bugs caused by gotime.Local (#13833)
This commit is contained in:
@ -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"
|
||||
)
|
||||
|
||||
@ -163,7 +164,13 @@ 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
|
||||
@ -171,7 +178,7 @@ func (s *testUtilSuite) TestDumpTextValue(c *C) {
|
||||
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
|
||||
|
||||
@ -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)
|
||||
@ -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))
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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()
|
||||
@ -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
|
||||
@ -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)
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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)
|
||||
@ -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
|
||||
@ -846,7 +853,7 @@ 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)
|
||||
@ -854,7 +861,7 @@ func (s *testTimeSuite) TestCompare(c *C) {
|
||||
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)
|
||||
@ -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)
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user