Spots

我实测了前端日期的 5 个坑:差 8 小时只是开始

日期处理是前端少有的「每个项目都要写、每个项目都写出 bug」的领域。我把最容易踩的 5 个坑写成一个实验脚本,在 UTC+8 的 Node 里逐个跑了一遍,下面每个症状都是真实输出,可以自己复跑。先看总账: 三种写法,三种结果(Node,UTC+8 实测): 第一行和第二行差 8 小时。不是 bug,是规范本身:ISO 格式里只有日期的字符串按 UTC 解析,带时间但没带时区的按本地时间解析。写代码的人觉得「这不就是个日期」,解析器认为「这是两种不同的东西」。

被坑的典型场景:表单里选了活动开始日 2026-03-15,前端 new Date(dateStr) 一转再传给后端,凭空多出 8 小时;或者接口返回…

被坑的典型场景:表单里选了活动开始日 2026-03-15,前端 new Date(dateStr) 一转再传给后端,凭空多出 8 小时;或者接口返回 2026-03-15T00:00:00Z,前端 .getDate() 直接取,东八区用户看是 15 号,换成负时区的海外用户就成 14 号了。 防御:别让「纯日期」过 Date。字符串直接存、直接传;非要算,就显式补时区('2026-03-15T00:00:00+08:00'),或者等文末的 Temporal。 坑 2:toISOString() 让日期变「昨天」 toISOString() 永远输出 UTC。本地 0:30(东八区)在 UTC 是前一天 16:30,slice 一刀下去,日期倒退一天。 本地开发在 UTC+8,CI 和容器默认 UTC,海外用户在负时区,同一段代码三个结果。「我本地好好的」这句话在日期 bug 里根本不成立。 防御:给人看的日期别用 toISOString。用 Intl.DateTimeFormat,时区可以显式传: toISOString 留给接口和日志这种给机器看的场景。 坑 3:空格写法,Safari 直接 Invalid Date 坑 1 的第三种写法(空格分隔)在规范里根本不存在。ES 只定义了 T 分隔,空格属于实现自定义行为,于是 V8 帮你兜了,Safari 不兜:

这个坑阴在测试不出来:开发机 Chrome 全绿,安卓机也绿,直到有人在 iPhone 上打开页面看到 NaN。Stack Overflow 上

这个坑阴在测试不出来:开发机 Chrome 全绿,安卓机也绿,直到有人在 iPhone 上打开页面看到 NaN。Stack Overflow 上 2010 年就有人问,社区修法一水儿的 replace(' ', 'T') 或 replace(/-/g, '/'): 更稳的做法是别喂字符串,字段拆开传:new Date(2026, 2, 15, 0, 0)。 坑 4:1 月 31 日加一个月,跳到 3 月 3 日 「下个月同一号」这种需求(续费提醒、账单日),setMonth 会直接溢出: 月份长度不一致,setMonth 只改月份数字,2 月装不下 31 日就往前进位。构造函数也一样沉默:不报错、不警告,日期悄悄变成下个月。 Java 默认给毫秒,Python 和 Unix 惯例是秒,接口文档不写清楚就各猜各的。现在的秒级时间戳是 10 位、毫秒级是 13 位,量级差 1000 倍。防御一行: 这条分界线(1e12,也就是 2001 年 9 月)离现在的两种时间戳都很远,够用到下个世纪。 最后三条是实验里顺手验证的:new Date(2026, 2, 1) 跑出来是 3 月 1 日;美国东部 2026-03-08(夏令时切换日)那天的两个本地零点间隔实测只有 23 小时,凌晨 1:30 加一小时直接落在 3:30。

回头看这 5 个坑的公共根源:Date 把「日期」和「时刻」混在一个类型里,字符串解析规则又叠了一层历史包袱。Temporal 把两件事拆开了,Node 26…

回头看这 5 个坑的公共根源:Date 把「日期」和「时刻」混在一个类型里,字符串解析规则又叠了一层历史包袱。Temporal 把两件事拆开了,Node 26 起默认启用(我这台 Node 24 要加 --harmony-temporal 才能用,刚试过): 纯日期用 PlainDate,时刻用 ZonedDateTime,坑 1 和坑 2 在类型层面就没了。Node 工具链现在就能试,浏览器端全面铺开之前,上面的防御写法还得再扛一阵。 这 5 个坑按「出现频率 × 隐蔽程度」挑的,实验脚本 40 行,换个 TZ 环境变量就能复跑。你踩过的是第几个、在什么场景发现的,评论区报个数。第 6 条留给你们补充。

News

我实测了前端日期的 5 个坑:差 8 小时只是开始

日期处理是前端少有的「每个项目都要写、每个项目都写出 bug」的领域。我把最容易踩的 5 个坑写成一个实验脚本,在 UTC+8 的 Node 里逐个跑了一遍,下面每个症状都是真实输出,可以自己复跑。先看总账: 三种写法,三种结果(Node,UTC+8 实测): 第一行和第二行差 8 小时。不是 bug,是规范本身:ISO 格式里只有日期的字符串按 UTC…

@spots
Source: Juejin
See more like this