SimpleDateFormat具有本地化模式的非法模式字符错误

时间:2016-06-20 11:25:44

标签: java localization simpledateformat

我试图理解一些SimpleDateFormat代码。特别是我试图在SimpleDateFormat中使用本地化的模式字符串。来自javadoc

  

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

它还指定了SimpleDateFormat(String pattern, DateFormatSymbols formatSymbols)构造函数:

  

使用给定的模式和日期格式符号构造SimpleDateFormat。

但是,尽管getLocalPatternChars()实例呈现了预期的模式字符,但SimpleDateFormat的构造函数拒绝包含这些字符的模式:

public void run() {
    Locale loc = new Locale("de", "de");
    DateFormatSymbols dfs = new DateFormatSymbols(loc);
    String sym = dfs.getLocalPatternChars();
    System.out.println(sym);
    SimpleDateFormat datefmt = new SimpleDateFormat("tt.MM.uuuu", dfs);
}

产生输出:

GuMtkHmsSEDFwWahKzZ
Exception in thread "main" java.lang.IllegalArgumentException: Illegal pattern character 't'
    at java.text.SimpleDateFormat.compile(SimpleDateFormat.java:845)
    ...

如果我用" ... new SimpleDateFormat("tt.MM.uuuu", loc);"替换最后一行,我会得到相同的输出。

另一方面,如果我使用任何Anglicized模式字符串创建SimpleDateFormat实例,然后调用" applyLocalizedPattern("tt.MM.uuuu")",则接受本地化模式。

因此,似乎不能在SimpleDateFormat的构造函数中使用本地化的模式字符串,并且需要这两步初始化。这是故意的行为吗?

2 个答案:

答案 0 :(得分:3)

不幸的是,如何处理本地化模式的文档非常糟糕。所以我研究了源代码并进行了自己的调查。结果:

SimpleDateFormat接受模式字符串的构造函数仅引用未定位的模式字符,其定义记录在类SimpleDateFormat的javadoc头中。这些未定位的模式字符也在DateTimeFormatSymbols

中定义为常量
/**
 * Unlocalized date-time pattern characters. For example: 'y', 'd', etc.
 * All locales use the same these unlocalized pattern characters.
 */
static final String  patternChars = "GyMdkHmsSEDFwWahKzZYuXL";

为了使用本地化模式需要三个步骤(比如“tt.MM.uuuu”你认为是德语 - 但不是德语,它应该是“TT.MM. JJJJ“ - JDK资源错误的例子:

  1. 通过DateFormatSymbols.setLocalPatternChars(...)定义本地化的模式字符。
  2. 使用SimpleDateFormat - 对象上的自定义日期格式符号。
  3. 通过SimpleDateFormat.applyLocalizedPattern(...)
  4. 应用本地化的日期时间模式

    然后,本地化模式将转换为内部和官方模式字符定义。

    使用示例(使用正确的德语模式TT.MM.JJJJ):

    SimpleDateFormat sdf = new SimpleDateFormat(); // uses default locale (here for Germany)
    System.out.println(sdf.toPattern()); // dd.MM.yy HH:mm
    System.out.println(sdf.toLocalizedPattern()); // tt.MM.uu HH:mm
    
    DateFormatSymbols dfs = DateFormatSymbols.getInstance(Locale.GERMANY);
    dfs.setLocalPatternChars("GJMTkHmsSEDFwWahKzZYuXL");
    sdf.setDateFormatSymbols(dfs);
    sdf.applyLocalizedPattern("TT.MM.JJJJ");
    
    System.out.println(sdf.toPattern()); // dd.MM.yyyy
    System.out.println(sdf.toLocalizedPattern()); // TT.MM.JJJJ
    System.out.println(sdf.format(new Date())); // 20.06.2016
    

    旁注:我已将字符串“GyMdkHmsSEDFWWahKzZYuXL”中的相应模式字符y和d更改为J和T,以进行本地化定义。

    不幸的是,JDK资源显然不可靠,所以我个人认为整个功能只能以笨拙的方式使用,在实践中不是很有用。

答案 1 :(得分:0)

尽管我同意@MenoHochschild对问题的分析,但提出的解决方案似乎比必要的更为复杂。我相信SimpleDateFormat上有一种名为applyLocalizedPattern的方法,相信会达到相同的结果。

String localizedPattern = ... // whatever localized pattern you have e.g. TT.MM.JJJJ
Locale locale = ... // whatever locale you are expecting the localized symbols to be, e.g. GERMAN

// Start with empty pattern (always valid)
SimpleDateFormat df = new SimpleDateFormat("", locale);

// Set the localized pattern (not possible via constructor)
df.applyLocalizedPattern(localizedPattern);

// Now, do whatever you want with that DateFormat object
String canonicalPattern = df.toPattern();

只要localizedPatternlocale彼此同意,该技术就适用于该用例。