当前位置: 首页 > news >正文

我被一个日期格式bug坑了,全球用户的时间全错了

上周上线了一个新功能,第二天收到全球用户反馈:时间显示全错了。
美国用户显示昨天,欧洲用户显示明天,亚洲用户有的对有的错。
排查了一整天,最后发现是一个简单的日期格式问题。
问题现象
功能是在线预约系统,用户选择时间后,服务器保存,再显示给用户。
测试环境没问题,上线后部分用户反馈时间不对。
排查过程
第一步:怀疑时区
服务器是UTC时间,用户本地有时区转换。但代码里已经做了时区处理,不应该有问题。
第二步:怀疑前端显示
前端用了 toLocaleString() ,但不同浏览器表现不一致。Chrome和Firefox差8小时,Safari正常。
第三步:发现真正原因
不是时区问题,是日期格式解析问题。
用户输入的是 2025-04-21 10:00 ,后端用 SimpleDateFormat 解析:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
Date date = sdf.parse(userInput);

问题出在用户输入格式不统一:
有的用户输入 2025/04/21 10:00 (斜杠)
有的输入 21-04-2025 10:00 (日月年)
有的输入 2025-04-21 (没有时分)
SimpleDateFormat 解析失败时,不会报错,而是静默解析成错误时间。
解决方案
改用 DateTimeFormatter ,严格匹配格式,解析失败直接报错:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(userInput, formatter);

或者更灵活,支持多种格式:

public LocalDateTime parseDate(String input) {
String[] patterns = {
"yyyy-MM-dd HH:mm",
"yyyy/MM/dd HH:mm",
"dd-MM-yyyy HH:mm"
};

for (String pattern : patterns) {try {return LocalDateTime.parse(input, DateTimeFormatter.ofPattern(pattern));} catch (DateTimeParseException e) {// 继续尝试下一个格式}
}
throw new IllegalArgumentException("无法解析日期: " + input);

}

前端统一
前端用 ,强制格式 yyyy-MM-ddTHH:mm ,减少用户输入错误。
教训
1.
不要信任用户输入,即使看起来格式正确
2.
解析失败要报错,不要静默处理
3.
前后端格式统一,避免转换错误
4.
全球化测试,至少测3个时区
数据影响
这次bug影响了约15%的全球用户,主要是手动输入时间的用户。自动填充的用户没问题。
修复后加了输入校验和格式提示,类似问题没再出现。

http://www.jsqmd.com/news/677637/

相关文章:

  • 避坑指南:AT32/STM32内部Flash模拟EEPROM,这些细节不注意数据会丢
  • 基于Django+Vue3与YOLO深度学习的火灾烟雾智能监测系统采用Django+Vue3前后端分离架构,含用户端与管理端界面,具备监控区域管理、火情记录归档、任务管理、智能问答、数据大屏、记录导出
  • Multisim里那些新手必踩的坑:从元件库找不到型号到仿真结果不对,一篇讲清避坑指南
  • 别下716GB了!用这个18GB的Light-HaGRID手势数据集,快速上手YOLOv5训练
  • Hermes Agent 使用与启动指南
  • 2026年值得合作的进口喉镜优质供应商推荐 - 品牌推荐大师1
  • 实地探访:四流喂丝机工厂在华北的布局,为何选择与 合作? - 新闻快传
  • LumenPnP开源贴片机完整指南:如何打造你的专属电子制造工作站
  • AI教材编写必备!低查重AI工具,轻松生成高质量教材内容!
  • 5个技巧让自动驾驶车辆在复杂路况下安全行驶:CILQR约束优化算法完全指南
  • 别再乱用kmalloc了!Linux内核驱动开发中内存分配函数的选择避坑指南
  • Proteus仿真有什么问题?怎么解决?
  • 告别单调界面:用ESP32和LVGL 8.1的Style背景API打造炫酷UI(附渐变/图片实战代码)
  • macOS窗口置顶终极指南:用Topit彻底释放多任务处理潜能
  • 豪城悦洁家政服务:亳州房屋渗水维修公司 - LYL仔仔
  • 如何快速掌握bilibili-downloader:新手也能上手的B站视频下载完整教程
  • MySQL外键怎么定义?数据关联怎么更清晰稳固?
  • 别再手动调优了!用RHEL/CentOS自带的Tuned工具,5分钟搞定Linux服务器性能配置
  • 收藏!小白/程序员快速上手大模型:Hermes Agent 完全指南与生态地图
  • tkinter按钮进阶玩法:从方形到圆角,详解TinyUI中button2的样式定制与事件绑定避坑指南
  • 2026年湖南长沙高端别墅装修与大平层全案定制服务对比指南 - 年度推荐企业名录
  • 为什么92%的Docker安全事件源于签名绕过?27步工业级验证流程,含cosign、notary v2、TUF三框架实测对比
  • EF Core 10向量索引如何与SQL Server 2022 HNSW无缝协同?——微软认证架构师披露内部性能调优参数表(含T-SQL向量化执行计划解读)
  • Douyin-Downloader:Python抖音批量下载工具的技术深度解析与实战指南
  • 泉州鼎盛拆除:泉州水泥黄沙出售电话 - LYL仔仔
  • fluent数值波高衰减怎么设置?为什么会出现衰减?
  • 告别NDT和ICP:用VoxelMap实现更鲁棒、更精准的LiDAR SLAM(附KITTI实测对比)
  • 别再手动拖菜单了!用Creo Toolkit自动化定制你的专属工作流菜单栏
  • LeaguePrank:5分钟打造你的专属英雄联盟形象
  • 机器人关节精密加工:GDT形位公差控制与装配卡滞对策深度解析 - 莱图加精密零件加工