JSON转Excel后18位订单号不对了?数字精度与类型边界实测

上周处理一件小事:把接口导出的订单数据交给运营做对账表。数据是 JSON 数组,直接贴进在线转换工具生成了 Excel,发出去半小时后运营找回来:前两行的订单号一模一样,财务系统按单号对账直接撞车。

我回头核对原始 JSON,两条订单的 order_no 分别是 202609031200301001 和 202609031200301002,明明是两个数。转出来的 Excel 里,这两行全变成了 202609031200301000。中间隔了半小时排查,最后发现这事和转换工具关系不大------数据在进入 Excel 之前就已经错了。把整个过程记下来,这个坑比想象中容易踩。

现象:错在解析那一步,不在 Excel

先把现象固定下来。用一份五行的订单数据做验证,每行的 order_no 都是 18 位整数:

json 复制代码
[
  { "order_no": 202609031200301001, "sku_code": "SKU0007", "goods_name": "机械键盘 87键 蓝牙双模", "qty": 2, "unit_price": 199.0, "paid": true, "coupon": null, "created_at": "2026-09-03 12:00:31" },
  { "order_no": 202609031200301002, "sku_code": "SKU0007", "paid": true, "coupon": 20.0, "created_at": "2026-09-03 12:05:18" },
  { "order_no": 202609031422180003, "sku_code": "SKU0012", "paid": false, "created_at": "2026-09-03 14:22:18" },
  { "order_no": 202609031630510014, "sku_code": "SKU0033", "paid": true, "coupon": 50.0, "created_at": "2026-09-03 16:30:51" },
  { "order_no": 202609041001220025, "sku_code": "SKU0041", "qty": 3, "paid": true, "created_at": "2026-09-04 10:01:22" }
]

贴进转换工具后,预览表格里的订单号就已经全变了。用浏览器控制台可以直接复现:

javascript 复制代码
JSON.parse('{"n": 202609031200301001}').n
// 202609031200301000

也就是说,JSON.parse 把这串文本读成 JavaScript 数值的那一刻,值就不是原来那个数了。工具前端用的同样是 JSON.parse,所以预览表格里的订单号已经不可信,后面导出成什么格式都救不回来。

为了排除"Excel 显示层"的嫌疑,我把导出的 xlsx 用 openpyxl 读回,直接看单元格里的存储值:

五条全部对不上,而且前两条在文件里就是同一个值。结论:不是 Excel 把数字显示错了,是写入的源头就是错的。...1001 和 ...1002 舍入后都是 ...1000,两个不同的数塌成了同一个数------这比"显示不全"严重得多,因为没有任何报错,下游根本不知道数据坏了。

为什么是 53 位:float64 的尾数边界

JavaScript 的 Number 按 IEEE 754 双精度(float64)存储,结构是 1 位符号、11 位指数、52 位尾数(加上隐含的首位 1,有效精度 53 位)。53 位二进制能精确表示的整数上限是:

复制代码
2^53 = 9007199254740992

这是 16 位数。18 位的订单号远超这个边界,超出之后浮点数只能按"最近的可表示数"取整。相邻的两个订单号 ...1001 和 ...1002,在 2^53 附近的数轴上,可表示数的间隔已经是 16 甚至 32,两个数落在同一个间隔里,就舍入成同一个值。

这也是为什么各种"最佳实践"反复强调:超过 2^53 的整数不要用 Number 类型承载 。雪花算法 ID(64 位)、18 位统一社会信用代码里的数字段、时间戳乘上随机数生成的订单号,全都落在这个雷区里。Java 后端用 Long 表示雪花 ID 没问题,但序列化成 JSON 给前端时,负责任的团队会把它写成字符串------Jackson 的 WRITE_NUMBERS_AS_STRINGS、Fastjson 的 @JSONField(serializeUsing) 这类配置存在的原因就在这。我见过有人把这种配置当成"前端兼容性玄学"删掉,现在算是补上了它防的是什么的实证。

还有一个容易混淆的层:Excel 单元格的数字按规范存 double,界面上只保证 15 位有效数字的显示精度。所以就算精度没在解析时丢,一个 18 位数字进了 Excel 也会显示成科学计数法或者被截断显示。也就是说,长数字过 Excel 这条路有两道精度关:JSON 解析是硬丢失(值永久改变),Excel 显示是软丢失(值还在,界面上看不全)。这次两道关都撞上了。

顺带验证的类型映射

精度之外,这次转换还把几种 JSON 类型在 xlsx 里的落点暴露得很清楚(同样用 openpyxl 逐格读回确认):

JSON 里的写法 xlsx 单元格实际存储 观察
202609031200301001(18位整数) 数值 202609031200301000 精度丢失,值已变
"SKU0007"(字符串) 文本 SKU0007 原样保留
true / false 文本 "true" / "false" 布尔降级成文本
null 空单元格 无内容
199.0 数值 199 .0 不存在了,float64 里 199.0 与 199 是同一个数
"2026-09-03 12:00:31" 文本原样 没有被转成日期序列值

几个点值得展开一句:

  • 199.0 变 199 不算丢数据------float64 里这两个字面量本来就是同一个值,只是 JSON 文本层面的写法差异在表格里被抹掉了。但如果是金额场景,"两位小数"的展示语义就没了,做表的人需要自己把单元格格式设回两位小数。
  • 布尔值变成文本 true/false 之后,在 Excel 里就不能再用 =IF(F2, ...) 这种逻辑判断了,得写成 =IF(F2="true", ...)。用这种表做二次加工的人会莫名其妙踩一下。
  • 时间戳字符串没有被自动识别成 Excel 日期(没有变成 5 位日期序列数),这反而省事------不会出现"转完日期全变成 45000 多"的经典问题。

规避办法

按数据流向,责任和手段都清楚:

  1. 源头(最优):后端序列化时就把长 ID 写成字符串。这一步做了,后面所有环节都安全。凡是"这串数字丢了会出事故"的值(订单号、支付流水号、雪花 ID、证件号码段),都应该按这个标准对待。
  2. 既有数据的补救 :拿到手的 JSON 已经是数字型长 ID 时,先在文本层面给它们加引号再解析。字段名固定的话,一条正则就够:"order_no":\s*(\\d{16,}) 替换成 "order_no": "$1"。改完再转,16 位以上的数字全程按文本走。
  3. 进 Excel 时:就算值是对的,长数字列也应该先设为文本格式再粘贴/导入,避开 15 位显示精度那一关。Excel 的"数据→分列"里选"文本"列格式,就是干这个的。

小结

这次排查的最终结论很简单:JSON.parse 在 2^53 边界外就有损,转换工具的预览和产物只是如实呈现了已经坏掉的数据;Excel 的 15 位显示精度是叠加的第二道关。判断"我的数据会不会踩",只需要看一眼最长的纯数字字段有没有超过 16 位。

验证过程我用的是工具派上的 JSON 转 Excel 工具,把上面那份订单数据完整跑了一遍,产物 xlsx 用 openpyxl 读回逐格核对,顺手记录一下。

相关工具地址:https://gjupai.com/tools/json_to_excel

相关推荐
阿皮 API3 小时前
Shopee虾皮商品详情API接口调用实战:Python获取东南亚商品数据与JSON解析
开发语言·python·json
死磕音视频4 小时前
让大模型稳定输出 JSON:结构化输出的三种方法与 Python 校验实践
json·大模型api·pydantic·结构化输出
今天的砖头有点烫手啊5 小时前
Java 序列化到底怎么选?从 Serializable 到 Protobuf 的演进与选型
java·json
小白学鸿蒙5 小时前
OpenHarmony 预置应用配置详解:/system/etc/app/ 下的 5 个 JSON
json·openharmony·预置应用
for_ever_love__6 小时前
LangChain 结构化输出:让模型稳定吐出符合 schema 的 JSON
langchain·json
健康活着就好6 小时前
# 手写Promise.all和Promise.race,面试再也不怕了
面试·json
Allstar_431 天前
制造业研发管理数字化:从 Excel 到专业 APQP 系统的架构选型思考
架构·excel
驾驭人生1 天前
NET NPOI 实战:生成带下拉、数据校验、必填标红的 Excel 导入模板
excel