OpenJDK 升级后日期/月份显示英文是因 jdk.localedata 模块未默认加载,需显式添加;jpackage 打包须加 --add-modules jdk.localedata,运行时需正确设置 LANG/LC_ALL 环境变量,并在 DateTimeFormatter 中调用 .withLocale()。

OpenJDK 升级后日期格式和语言区域行为变化,不是 bug,而是模块化与默认 locale 数据加载策略调整的直接结果。最常见于从 JDK 8/11 升级到 JDK 17+,尤其是使用 jpackage 打包或在精简运行时(如自定义 JRE)中运行时。
为什么升级后 Locale 显示的星期/月份突然变英文了
核心原因是:JDK 9+ 实施模块化后,jdk.localedata 模块不再默认包含在运行时镜像中。旧版 JDK(如 8)把所有语言数据硬编码进 rt.jar;而新版 JDK 把中文、西班牙语等 locale 数据拆成独立模块,必须显式声明依赖,否则 DateTimeFormatter 或 SimpleDateFormat 在非系统默认 locale 下会回退到根语言环境(Locale.ROOT),显示英文名称。
- 现象:代码里写了
new Locale("zh", "CN"),但formatter.format(LocalDate.now())中的“星期三”仍显示为Wednesday - 验证方式:运行
java --list-modules | grep locale,若无输出或不含jdk.localedata,即确认缺失 - 影响范围:所有依赖
java.time.format或java.text的国际化格式化逻辑,不限于 JavaFX
jpackage 打包时漏掉 jdk.localedata 模块
用 jpackage 构建独立应用时,它默认只包含主模块及其静态可分析的依赖,jdk.localedata 属于“按需加载”的资源模块,不会被自动识别和打包。
- 修复命令:在
jpackage后追加--add-modules jdk.localedata - 若指定了
--limit-modules,必须把jdk.localedata加进去,例如:--limit-modules java.base,javafx.controls,jdk.localedata - 对多语言支持更稳的做法:加上
--bind-services,它会主动探测并包含服务提供者(包括 locale data 服务) - 验证打包结果:解压生成的 runtime 目录,检查
lib/modules文件是否存在,再用jmod list jdk.localedata.jmod | head -5确认内容
运行时未正确设置系统级 LANG 或 LC_* 环境变量
即使代码里硬编码了 Locale.CHINA,某些 JDK 内部路径(比如 DateFormatSymbols.getInstance() 的 fallback 行为)仍会读取系统环境变量。Linux/macOS 上若未设 LANG=zh_CN.UTF-8,JDK 可能无法定位到对应语言包索引。
- 临时验证:启动应用前执行
export LANG=zh_CN.UTF-8,再运行 jar,看问题是否消失 - 生产部署建议:在启动脚本中固化该设置,不要依赖用户会话环境
- 注意
LC_TIME等单项变量:如果只设LANG但LC_TIME=en_US.UTF-8,日期格式仍可能走英文——应统一设为zh_CN.UTF-8或留空继承LANG - 容器场景:Dockerfile 中需显式
ENV LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8,并确保基础镜像已安装对应 locale 包(如 Debian 系用locales-all)
JavaFX TableCell 中 DateTimeFormatter 不生效的典型陷阱
这个场景特别容易误判为 locale 问题,实则常因 formatter 实例复用或线程上下文错位导致。
- 错误写法:在
updateItem外部创建 formatter,但没绑定 locale ——DateTimeFormatter.ofPattern("dd/MM/yyyy E")默认用系统 locale,而非代码中指定的那个 - 正确写法:必须调用
.withLocale(locale),且 locale 对象不能为 null;示例:DateTimeFormatter.ofPattern("yyyy年MM月dd日 E").withLocale(Locale.CHINA) - 避免在 CellFactory 中反复 new formatter:开销小但易出错,建议提取为
static final字段 - Android 或 Swing 开发者要注意:JavaFX 的
TableCell不受系统配置变更广播影响,切换语言需手动刷新 cell factory 或重置整个 TableView
真正棘手的点在于:问题表现是“语言不对”,但根源可能是模块缺失、环境变量覆盖、formatter 构造遗漏、甚至 JVM 启动参数(如 -Duser.language)与代码冲突。排查时别只盯着代码里的 Locale,先确认运行时到底加载了哪些 locale 模块,再逐层验证链路是否被中途截断。











