beego mysql按时间排序_beego orm中时区的问题

先看简化后代码,下面只列出main函数

func main() {

t := "2017-01-19 00:00:00"

o := orm.NewOrm()

qb, _ := orm.NewQueryBuilder("mysql")

sql := qb.Select("COUNT(*)").From("test").Where("create_time > ?").String()

o.Raw(sql, t).Exec()

o.QueryTable("test").Filter("create_time__gt", t).Count()

}

这么看的话感觉两个SQL应该是相同的:

[ORM] - 2017-01-19 19:28:02 - [Queries/default] - [ OK / db.Exec / 1.2ms] - [SELECT COUNT(*) FROM test WHERE create_time > ?] - `2017-01-19 00:00:00`

[ORM] - 2017-01-19 19:28:02 - [Queries/default] - [ OK / db.QueryRow / 2.3ms] - [SELECT COUNT(*) FROM `test` T0 WHERE T0.`create_time` > ? ] - `2017-01-19 00:00:00`

我在本机测试OK,但在另一个环境SQL是这样的:

[ORM] - 2017-01-19 11:30:43 - [Queries/default] - [ OK / db.Exec / 1.2ms] - [SELECT COUNT(*) FROM test WHERE create_time > ?] - `2017-01-19 00:00:00`

[ORM] - 2017-01-19 11:30:43 - [Queries/default] - [ OK / db.QueryRow / 1.2ms] - [SELECT COUNT(*) FROM `test` T0 WHERE T0.`create_time` > ? ] - `2017-01-19 08:00:00`

相差8小时,第一时间想到时区问题,去有问题的环境一看果真如此。

然后看了下beego orm的代码,下面列出关键部分。

1.orm/db_utils.go的getFlatParams()

此函数是解析Filter()生成SQL的关键部分,如果Filter()第一个参数类型是Date或Datetime,第二个参数类型是string就把string解析成time.Time类型

在上面case中len(v) = 19,执行time.ParseInLocation(formatDateTime, s, DefaultTimeLoc),因为有问题的环境是UTC时区,所以此函数会把字符串2017-01-19 00:00:00解析成time.Time2017-01-19 00:00:00 +0000 UTC(变量t,但实际是东八区的时间,正确的t应该是2017-01-19 00:00:00 +0800 CST)。

func getFlatParams(fi *fieldInfo, args []interface{}, tz *time.Location) (params []interface{}) {

……

switch kind {

case reflect.String:

v := val.String()

if fi != nil {

if fi.fieldType == TypeDateField || fi.fieldType == TypeDateTimeField {

var t time.Time

var err error

if len(v) >= 19 {

s := v[:19]

t, err = time.ParseInLocation(formatDateTime, s, DefaultTimeLoc)

} else {

s := v

if len(v) > 10 {

s = v[:10]

}

t, err = time.ParseInLocation(formatDate, s, tz)

}

if err == nil {

if fi.fieldType == TypeDateField {

v = t.In(tz).Format(formatDate)

} else {

v = t.In(tz).Format(formatDateTime)

}

}

}

}

arg = v

……

}

2.t.In(tz).Format(formatDateTime)再次将t格式化为字符串,参数tz是关键,它是在下面代码中赋值的。因为MySQL设置的是东八区,所以会设置al.TZ为东八区,也就是t.In(tz).Format(formatDateTime)中tz是东八区,导致Format返回的字符串是2017-01-19 08:00:00,于是就有了上面两条SQL不同的问题。

func detectTZ(al *alias) {

// orm timezone system match database

// default use Local

al.TZ = time.Local

......

switch al.Driver {

case DRMySQL:

row := al.DB.QueryRow("SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP)")

var tz string

row.Scan(&tz)

if len(tz) >= 8 {

if tz[0] != '-' {

tz = "+" + tz

}

t, err := time.Parse("-07:00:00", tz)

if err == nil {

al.TZ = t.Location()

} else {

DebugLog.Printf("Detect DB timezone: %s %s\n", tz, err.Error())

}

}

......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值