ZonedDateTime t = instant.atZone(ZoneId.of("Asia/Tokyo"));
LocalDate d = t.toLocalDate();

东京时间 2026-01-01 00:30 的订单,详情页显示 2025-12-31,年度报表把这笔算进上一年,差了 1 天。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。

原因不复杂,时间在数据库里是带时区的,取出来后先转成 UTC 再截成 LocalDate,日期就退了一天。格式化又用了 JVM 默认时区,两个转换叠在一起。订单归属年份按展示日期算,错误被带进报表。

「日期时区叠加」排查到最后往往是很小的一处差异,前面那些复杂猜测可以先放一放。改动写完就同步给同事,下一个人踩同一个坑,成本还是你的。

验证用真实数据走一遍,测试数据太干净,边界情况根本碰不到。能分两步做的操作就别合成一步,中间看一眼返回值,出问题好判断。

处理上按这个顺序:按用户时区取 LocalDate 不要先转 UTC;统一用 ZoneId.of("Asia/Tokyo") 显式转换;年度归属用订单业务时区 不用展示时区;拿 00:30 和 23:30 两个边界各下一单 对比年份。

改完只确认一件事:东京 2026-01-01 00:30 的订单显示 2026-01-01,年度报表归到 2026 年。

作者 9823189