Beego ORM 查询日期范围需用 Filter("field__gte", start).Filter("field__lte", end),不支持__between;推荐传 time.Time 类型并配置 orm.DefaultTimeLoc 与数据库时区一致,避免字符串硬编码导致的时区和格式问题。

Beego ORM 的 QueryTable().Filter() 怎么写日期范围条件?
Beego ORM 不支持直接用 BETWEEN 语法,必须拆成两个独立的比较条件组合使用。常见错误是写成 .Filter("created_at__between", start, end) —— 这会报错,因为 Beego ORM 原生不识别 __between 后缀。
正确做法是用 __gte(greater than or equal)和 __lte(less than or equal)拼接:
o := orm.NewOrm()
var logs []Log
qs := o.QueryTable(&Log{})
qs = qs.Filter("created_at__gte", "2024-01-01 00:00:00").Filter("created_at__lte", "2024-01-31 23:59:59")
qs.All(&logs)
- 时间字符串格式必须严格匹配数据库字段类型:MySQL
DATETIME接受"Y-m-d H:i:s",TIMESTAMP可能自动转时区,建议统一用time.Time类型传参更安全 - 如果字段是
DATE类型(无时分秒),用"2024-01-01"即可,但注意 MySQL 会隐式补全为"2024-01-01 00:00:00",查当天数据时别漏掉__lte上界 - Beego ORM 默认对
time.Time值做 UTC 转换,若数据库存的是本地时间(如Asia/Shanghai),需在初始化 ORM 时设置时区:orm.DefaultTimeLoc = time.Local
用 time.Time 变量做范围查询更可靠
硬编码字符串容易出时区、格式、边界问题。推荐用 Go 原生 time.Time 构造起止时间,再传给 Filter:
start := time.Date(2024, 1, 1, 0, 0, 0, 0, time.Local)
end := start.AddDate(0, 0, 7).Add(-1 * time.Second) // 7天区间,含首尾
<p>qs := o.QueryTable(&Log{})
qs = qs.Filter("created_at__gte", start).Filter("created_at__lte", end)
qs.All(&logs)
</p>
-
time.Local必须和数据库实际存储时区一致,否则查不到数据 - 用
Add(-1 * time.Second)替代手动拼"23:59:59",避免跨天或闰秒误差 - 如果字段类型是
DATE,Beego ORM 会自动截断time.Time的时分秒部分;但若数据库是DATETIME,且你只想查某天的全部记录,仍需显式指定00:00:00到23:59:59
为什么 Filter("created_at__gt", ...) 查不到数据?
常见原因是字段类型与传入值类型不匹配,或时区导致时间被平移。比如:
- 数据库字段是
TIMESTAMP(自动转 UTC 存储),而你传了time.Local时间 → ORM 会再转一次 UTC,结果偏移 8 小时 - 字段是
DATETIME,但没设orm.DefaultTimeLoc→ 默认按 UTC 解析,导致查询时间比预期早 8 小时 - 传了字符串
"2024/01/01"(斜杠分隔)→ Beego ORM 内部解析失败,静默忽略该条件,只执行另一半过滤
调试方法:开启 ORM 日志,看生成的 SQL 是否符合预期:orm.Debug = true。重点关注 WHERE 子句里的时间值是否是你期望的。
复杂场景:联合其他条件 + 分页 + 排序
日期范围只是查询的一部分,实际常要叠加状态、用户 ID 等条件。注意链式调用顺序不影响逻辑,但影响可读性:
qs := o.QueryTable(&Log{})
qs = qs.Filter("status", 1).
Filter("user_id", 123).
Filter("created_at__gte", start).
Filter("created_at__lte", end).
OrderBy("-created_at").
Limit(20).
Offset(0)
qs.All(&logs)
-
OrderBy("-created_at")中的负号表示降序,别漏掉 -
Limit和Offset要放在最后,否则可能被前面的Filter影响计数(Beego ORM 的Count()不受Limit影响,但All()会) - 如果需要总条数,单独调一次
qs.Count(),不要依赖All()返回长度——分页时两者不等
时区配置和时间类型一致性是多数人卡住的地方,不是语法写不对,而是时间“看起来一样,其实差八小时”。











