Beego ORM时间筛选必须用time.Time类型字段配__gte/__lte表达式,传字符串会静默失败;需加type(datetime) tag、用指针判空、闭开区间防跨天漏数据。

Beego ORM 的 Filter() 支持日期/时间范围筛选,但必须用双下划线表达式(如 created__gte),且字段类型需为 time.Time 或数据库原生 datetime/timestamp 类型;直接传字符串会静默失败或查出空结果。
日期字段必须定义为 time.Time 类型,且带正确 tag
Beego ORM 不会自动把字符串转成时间,也不会按字符串字典序比较。如果模型里写的是 Created string,哪怕数据库存的是 "2024-01-01 10:20:30",Filter("created__gte", "2024-01-01") 也大概率不生效——ORM 会当成普通字符串模糊匹配,或因类型不匹配跳过条件。
- ✅ 正确写法:
CreatedAt time.Time `orm:"column(created_at);type(datetime)"` - ✅ 若字段允许 NULL,用指针:
UpdatedAt *time.Time `orm:"column(updated_at);type(datetime);null"` - ❌ 错误写法:
Created string `orm:"column(created)"`(即使数据库是 datetime 类型也不行) - ⚠️ 注意:Beego 会忽略未加
type(datetime)tag 的time.Time字段,仍当字符串处理
__gte、__lte 等时间表达式必须配合 time.Time 值使用
虽然文档里常看到 Filter("created__gte", "2024-01-01") 这种写法,但这是历史遗留的“碰巧能用”——底层实际依赖数据库隐式转换,跨 MySQL/PostgreSQL/SQLite 表现不一致,且无法校验格式。真实项目中应始终传 time.Time 实例。
- ✅ 安全写法:
qs.Filter("created_at__gte", startTime).Filter("created_at__lte", endTime),其中startTime,endTime是time.Time类型 - ✅ 解析用户输入时用
time.ParseInLocation(),指定时区(别用time.Parse(),它默认 UTC):t, _ := time.ParseInLocation("2006-01-02 15:04:05", input, time.Local) - ❌ 危险写法:
Filter("created_at__gte", r.FormValue("start"))—— 字符串直接进条件,无类型保障 - ⚠️ 注意:
__range表达式 Beego ORM 不支持(GORM 有,Beego 没有),只能拆成两个__gte+__lte
空值和零值必须显式过滤,否则 time.Time{} 会被当 0001-01-01 查询
Go 的 time.Time 零值是 0001-01-01 00:00:00 +0000 UTC。如果表单没填时间,又没做判空,Filter("created_at__gte", userTime) 就会查 “所有创建时间晚于公元元年的记录”,等效全表扫描。
- ✅ 推荐模式:用指针接收 + 判 nil:
if start != nil { qs = qs.Filter("created_at__gte", *start) } - ✅ 或用非零判断:
if !userTime.IsZero() { qs = qs.Filter("created_at__gte", userTime) } - ✅ 表单解析后立即校验:
if t, err := time.ParseInLocation(...); err == nil { startTime = &t } - ⚠️ 注意:
time.Time的IsZero()判断的是是否为零值,不是是否为空字符串
跨天查询要小心时区和时间精度
用户选 “2024-10-01 至 2024-10-01”,本意是查当天全部记录,但若直接用 __gte/__lte 套两个 time.Time,容易漏掉 2024-10-01 23:59:59.999 的数据(因精度丢失或时区偏移)。
- ✅ 查单日推荐用
__gte+__lt闭开区间:qs.Filter("created_at__gte", dayStart).Filter("created_at__lt", dayStart.Add(24*time.Hour)) - ✅
dayStart应截断到秒级并归零:dayStart = time.Date(y, m, d, 0, 0, 0, 0, time.Local) - ✅ 数据库字段用
datetime(非date),避免 MySQL 的date类型隐式丢弃时间部分 - ⚠️ 注意:Beego 不支持
__date这类 Django 风格表达式,想按日期查必须靠Raw()或应用层截断
最易被忽略的一点:Beego ORM 的时间条件生成 SQL 时,不会自动加引号或类型转换,全靠 Go driver 和数据库自己解析。一旦模型字段类型、tag、传入值三者不严格对齐,就可能查不到数据且无报错——建议在开发期打开 orm.Debug = true,眼见为实看生成的 SQL 是什么。











