日期怎么存怎么比
MongoDB 的 Date 是 BSON 日期类型,内部存 UTC 毫秒时间戳(自 1970-01-01 起的整数),与时区无关。mongosh 里的 ISODate("...") 就是 JS Date 的别名,查询时按 UTC 换算区间,展示时才按本地时区渲染。
基本信息
| 适用版本 | MongoDB 4.x-8.x / mongosh |
|---|---|
| 存储格式 | BSON Date,UTC 毫秒 |
| 构造方式 | ISODate("2026-10-01T00:00:00Z") / new Date(毫秒数) |
| 区间查询 | $gte + $lt 组成半开区间 |
| 精度 | 毫秒,无纳秒/微秒 |
典型使用场景
- 按天/按小时统计:先用 UTC 区间框住数据,再用 $dateToString 指定时区格式化
- 增量抽取与对账:用 updatedAt 区间拉数据,半开区间避免边界重复
- TTL 自动清理:对 Date 字段建 expireAfterSeconds 索引,到期自动删文档
- 分页排序:按 ts 倒序翻页,用 (ts, _id) 组合保证顺序稳定
- 跨时区系统统一口径:入库统一 UTC,展示层再转北京时间
查一天数据
查一天数据
db.orders.find({ ts: { $gte: ISODate("2026-10-01T00:00:00Z"), $lt: ISODate("2026-10-02T00:00:00Z") } }) # UTC 自然日
db.orders.find({ ts: { $gte: new Date("2026-10-01T08:00:00+08:00") } }) # 带偏移量,等价 UTC 00:00
db.orders.find({ ts: { $gte: new Date(Date.now() - 24*3600*1000) } }) # 最近 24 小时窗口
db.orders.aggregate([ { $group: { _id: { $dateToString: { format: "%Y-%m-%d", date: "$ts", timezone: "+08:00" } }, n: { $sum: 1 } } } ]) # 按北京时间归日常见写法与含义
| 写法 | 含义 | 注意点 |
|---|---|---|
| ISODate("2026-10-01T00:00:00Z") | 带 Z 的 UTC 时间点 | 最明确,跨时区场景优先用这种 |
| ISODate("2026-10-01") | 按 UTC 零点解释 | 不会自动按本地时区,容易差 8 小时 |
| new Date("2026-10-01T08:00:00+08:00") | 带偏移量的本地时间点 | 等价 UTC 00:00,可读性好 |
| Date.now() | 当前毫秒时间戳 | 可直接做算术,如减去 7 天 |
| "2026-10-01" | 字符串类型,不是日期 | 与 Date 字段比较不会按预期命中 |
字符串和日期类型不互通:拿 "2026-10-01" 这样的字符串去比较 Date 字段,BSON 类型排序决定结果永远不符合业务预期,必须显式转换(new Date(...) 或 $dateFromString)。
需要范围查询、排序、TTL 过期或者聚合分组的字段,一定要存成 Date 而不是字符串;字符串存时间只能在写入端做格式化,查询侧基本失能。
查询北京时间 2026-10-01 这整天,对应 UTC 区间是 2026-09-30T16:00:00Z 到 2026-10-01T16:00:00Z;直接用 Z 零点当北京时间零点,会漏掉最前面 8 小时的数据。
mongosh 打印 ISODate 时按本机时区渲染,同一份文档在不同时区的机器上打印出的字符串不一样,但存储值与比较结果始终基于 UTC。核对对错请看 $gte/$lt 的边界,别拿打印出来的字面时间当依据。