Java日期格式化非法模式字符'y'。

13

最近我们在生产环境中遇到了奇怪的错误(测试环境正常运行)。

java.lang.IllegalArgumentException: 非法的模式字符'y'

这是由以下代码引起的。

SimpleDateFormat dateFormat = (SimpleDateFormat)DateFormat.getDateInstance();
dateFormat.applyLocalizedPattern("yyyy-MM-dd");

通常,当年份使用'Y'而非'y'时,会抛出此错误。但是,正如您在上面看到的那样,这不是本案例的情况。我不能确定服务器上设置的语言环境是否正确。Linux环境的LANG设置为“de_DE.UTF_8”,因此可能被使用。

进入SimpleDateFormat.java源代码,我找到了方法translatePattern(String pattern, String from, String to)。当pattern中的任何字符不存在于from中时,就会抛出上述异常。本地在另一台计算机上进行调试时,值看起来像这样:

pattern =“yyyy-MM-dd”
from =“GyMdkHmsSEDFwWahKzZ”

从服务器上的异常中可以看出,第一个“y”不存在于from中。from是从formatData.getLocalPatternChars()获取的,该方法是由从服务器获取的区域设置初始化的DateFormatSymbols

有没有可用的区域设置可以没有“y”的格式?这个错误已经开始出现,没有任何代码更改,并且根据我的知识,服务器配置也没有更改。


你正在运行哪个精确的JVM? - Thorbjørn Ravn Andersen
java.vm.specification.vendor: Sun Microsystems Inc. java.runtime.version: 1.6.0_37-b06 - Rasmus Franke
它和在测试中运行的那个完全一样吗? - Thorbjørn Ravn Andersen
是的,我解决了这个问题,原因在于一个初始化问题,通常会设置某个特定的语言环境,但它没有被正确地调用。 - Rasmus Franke
您的瑞典-德国语言环境设置不太常见,您可能考虑在问题中包含此类信息。在这样的服务器上安装美式英语操作系统以避免不常见的配置并不罕见。 - Thorbjørn Ravn Andersen
当我提出问题时,我并不清楚确切的设置。我们的操作系统设置为en_US,但在jvm的启动脚本中被覆盖为de_DE,然后在应用程序中又被覆盖为sv_SE(失败了)。 - Rasmus Franke
2个回答

11

从SimpleDateFormat javadoc中得知:

SimpleDateFormat还支持本地化的日期和时间模式字符串。在这些字符串中,上面描述的模式字母可以被替换为其他与语言环境相关的模式字母。

在您的情况下,语言环境是DE,因此本地化的模式将是jjjj-MM-ttJ代表年份,T代表天数。

如果您不想处理本地化的模式,请使用SimpleDateFormat.applyPattern("yyyy-MM-dd")


谢谢,我想我刚刚找到了错误......我们将服务器语言环境设置为德语,但在初始化servlet中覆盖为瑞典语。我认为当生产昨天重新启动时,初始化可能已经崩溃,我们被困在德语环境中! - Rasmus Franke

8

理想情况下,您应该强制使用模式的区域设置,否则您的模式需要针对不同的区域进行更改,例如yyyy适用于en_US,jjjj适用于de_DE等。相反,仅指定yyyy和区域设置为en_US,而与您机器的区域设置无关。

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
System.out.println(format.format(new java.util.Date()));

根据javadoc文档:
使用给定的模式和默认日期格式符号来构造SimpleDateFormat。注意:此构造函数可能不支持所有语言环境。为了实现完全覆盖,请使用DateFormat类中的工厂方法。
参数: pattern:描述日期和时间格式的模式 locale:应使用其日期格式符号的语言环境
这样做的好处是,您无需担心运行时语言环境选择哪个本地字符串,也无需强制指定特定的语言环境。

是的,我同意,我提到的代码是2007年的,不是我编写的。我们确实在服务器上强制执行区域设置,但由于一个失败的集成使初始化在调用locale.setDefault(new Locale("sv", "SE"))之前崩溃,导致使用了服务器默认的德语 :) - Rasmus Franke
如果你要维护这段代码,你可能想让初始化错误变成致命错误,这样应用程序就会拒绝运行。 - Thorbjørn Ravn Andersen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接