首页 / MongoDB 入门教程 / 日期、时区与 Decimal128 精度

MongoDB 入门教程

日期、时区与 Decimal128 精度

本教程共 50 篇 · 第 10 篇 · 更新于 2026-07-30 · 约 7 分钟阅读

MongoDBMongoDB 入门教程ISODate时区Decimal128浮点精度

10. 日期、时区与 Decimal128 精度

本节目标:搞懂 MongoDB 怎么存时间(UTC)、应用层怎么处理时区,以及金额为什么必须用 Decimal128 而不是普通小数。

10.1 日期用 ISODate

MongoDB 的日期类型是 ISODate,写起来像这样:

// 写入一个时间
db.orders.insertOne({
  _id: 1001,
  created_at: ISODate("2024-01-15T08:30:00Z")
})
Note

据 MongoDB 8.3 官方文档,BSON Date 类型是「UTC datetime」:底层是一个 64 位整数,表示从 Unix 纪元(1970-01-01)起的毫秒数。

10.2 时间存的是 UTC

关键点:MongoDB 内部统一按 UTC(世界协调时)存日期。你写进去的本地时间,会被换算成 UTC 存。

// 上海时间 16:30,等价于 UTC 08:30
db.orders.insertOne({ created_at: ISODate("2024-01-15T16:30:00+08:00") })

// 读出来看到的是 UTC
db.orders.findOne().created_at
ISODate("2024-01-15T08:30:00Z")

所以时区的处理责任在「应用层」:存的时候转 UTC,显示的时候再按用户所在时区格式化。

Tip

最佳实践:所有时间都存 UTC,只在展示给用户时做时区转换。这样跨国业务不会对账出错。

10.3 时区常见坑

我踩过的坑:两个用户一个在北京、一个在纽约,同一时刻下单,如果用各自本地时间存,查「今天订单」就会乱。

  • 存:统一转成 UTC 再写。
  • 查范围:查询条件也用 UTC 时间。
  • 显示:读出来后按用户时区格式化,库里不动。
// 查 2024-01-15 全天(UTC 视角)
db.orders.find({
  created_at: {
    $gte: ISODate("2024-01-15T00:00:00Z"),
    $lt:  ISODate("2024-01-16T00:00:00Z")
  }
})

10.4 为什么金额不能用 Double

普通小数 19.99 在 MongoDB 里是 Double(双精度浮点)。浮点无法精确表示很多十进制小数。

// 浮点的老问题:0.1 + 0.2 不等于 0.3
0.1 + 0.2
0.30000000000000004

金额累加几千笔后,差额会肉眼可见。对账差一分钱,财务会找你。

10.5 Decimal128 解决精度

Decimal128 是 128 位十进制浮点,专为精确小数设计。

Note

据 MongoDB 8.3 官方文档,Decimal128 支持 34 位十进制有效数字,指数范围 -6143 到 +6144,适合货币、税务、科学计算等对舍入敏感的场景。

写法是用 NumberDecimal(),且建议把值当字符串传,避免先被浮点污染:

// 用 NumberDecimal 存金额,传字符串保精度
db.orders.insertOne({
  _id: 1001,
  total: NumberDecimal("377.00"),
  status: "paid"
})

查询和运算都按数值来,精度不丢:

// 找金额大于 100 的订单
db.orders.find({ total: { $gt: NumberDecimal("100.00") } })
Warning

同一个字段别混用 Double 和 Decimal128。混了之后相等判断和排序可能出意外。要么全用 Decimal128,要么全用 Double,保持一致。

10.6 Double 还是 Decimal128

一句话总结:

  • 计数、评分、温度这类「近似也无妨」的数值,用 Double 没问题。
  • 钱、税率、利率这类「差一分都不行」的数值,用 Decimal128。
// 用 products 集合演示:价格用高精度小数更稳妥
db.products.insertOne({
  _id: 1,
  name: "机械键盘",
  price: NumberDecimal("399.99"),
  category: "外设",
  stock: 50,
  tags: ["hot"]
})