Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SimpleDateFormat Illegal pattern character error with localized pattern

I'm trying to understand some SimpleDateFormat code. In particular I'm trying to use localized pattern strings in SimpleDateFormat. From the javadoc:

SimpleDateFormat also supports localized date and time pattern strings. In these strings, the pattern letters described above may be replaced with other, locale dependent, pattern letters.

It also specifies a SimpleDateFormat(String pattern, DateFormatSymbols formatSymbols) constructor:

Constructs a SimpleDateFormat using the given pattern and date format symbols.

However, although getLocalPatternChars() instance is presenting the expected pattern characters, SimpleDateFormat's constructors are rejecting patterns containing those characters:

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);
}

produces output:

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

I get the same output if I replace the last line with "... new SimpleDateFormat("tt.MM.uuuu", loc);".

On the other hand, if I create a SimpleDateFormat instance using any Anglicized pattern string, then call "applyLocalizedPattern("tt.MM.uuuu")", the localized pattern is accepted.

So it appears that one cannot use a localized pattern string in SimpleDateFormat's constructors, and need this two-step initialization. Is this intentional behaviour?

like image 894
Bob Arthur Avatar asked Jun 20 '16 11:06

Bob Arthur


1 Answers

Unfortunately the documentation of how to handle localized patterns is horrible. So I studied the source code and made my own investigations. Result:

The constructor of SimpleDateFormat accepting a pattern string only refers to the unlocalized pattern characters whose definition is documented as given in the javadoc header of class SimpleDateFormat. These unlocalized pattern characters are also defined as constant in 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";

Three steps are necessary in order to use localized patterns (like "tt.MM.uuuu" what you believe to be German - but is NOT German, it should rather be "TT.MM.JJJJ" - example for wrong JDK resources):

  1. Define the localized pattern characters via DateFormatSymbols.setLocalPatternChars(...).
  2. Use the customized date-format-symbols on your SimpleDateFormat-object.
  3. Apply the localized date-time-pattern via SimpleDateFormat.applyLocalizedPattern(...)

Then the localized pattern will be translated to the internal and official pattern character definition.

Example of usage (using the correct German pattern 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

Side note: I have changed the appropriate pattern chars y and d to J and T in the string "GyMdkHmsSEDFwWahKzZYuXL" to make a localized definition.

Unfortunately the JDK resources are obviously not reliable so my personal view is that the whole feature can only be used in an awkward way and is not very useful in practice.

like image 151
Meno Hochschild Avatar answered Oct 17 '22 08:10

Meno Hochschild