Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change DateFormatSymbols in JDK8 to solve incompatibility with JDK7 (genitive month names)?

As Xaerxess found in this topic: Month name in genitive (Polish locale) with Joda-Time DateTimeFormatter in JDK8 DateFormatSymbols.getInstance(new Locale("pl", "PL")).getMonths() returns month names in genitive by default. Previous Java version returns month names in nominative case. With this, for example, SimpleDateFormat format with "dd-MMMM-yyyy" pattern gives different result in JDK8 than in JDK6 or 7.

It's a big change and some of my old application doesn't work properly with a new month names. I'm looking for a solution to change globally default month names for Locale PL.

I tried with DateFormatSymbols.getInstance().setMonths(new String[] {..}), but it doesn't work globally.

If I'll find a solution for changing default month names with Java code, I could add this code at application initialization, without correcting the whole app. In my case I'll just simply add an servlet to my web app with load-on-startup option.

Or maybe you have a different idea how to make Java 8 compatible in this case? Maybe there is parameter / option which I could pass to jvm on start?

like image 594
Jakub Królikowski Avatar asked May 17 '15 11:05

Jakub Królikowski


1 Answers

I had the same issue. Of all the billion standards my client decided to use all capital letters for the month breaking the default parsers. So my date looked like:

02-DEC-15

Now Java time can Parse "Dec" but not "DEC". Annoying .. I searched for a while and found the java8 replacement for this problem.

This is how you can add custom anything to your formatter:

public static void main(String[] args) {
    String test = "02-DEC-15";

    Map<Long, String> lookup = new HashMap<>();
    lookup.put(1L, "JAN");
    lookup.put(2L, "FEB");
    lookup.put(3L, "MAR");
    lookup.put(4L, "APR");
    lookup.put(5L, "MAY");
    lookup.put(6L, "JUN");
    lookup.put(7L, "JUL");
    lookup.put(8L, "AUF");
    lookup.put(9L, "SEP");
    lookup.put(10L, "OCT");
    lookup.put(11L, "NOV");
    lookup.put(12L, "DEC");

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                                      .appendPattern("dd-")
                                      .appendText(ChronoField.MONTH_OF_YEAR, lookup)
                                      .appendPattern("-yy")
                                      .toFormatter();

    LocalDate parse = LocalDate.parse(test,formatter);
    System.out.println(parse);
}

This is a bit tricky because it did not behave the way I expected it. Here's a few points to consider:

Each append call will add a new parser instance that will be called IN ORDER strictly failing if it does not work. So for example, if you take the above example and thought you could just add months, saying:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                                  .appendPattern("dd-MMM-yy")
                                  .appendText(ChronoField.MONTH_OF_YEAR, lookup)
                                  .toFormatter();

This will fail, because the pattern adds multiple parsers for your formatter:

dd
-
MMM
-
yy

Adding the lookup at the end won't work, because MMM will already fail your parsing context.

Each step can therefore be added separately. Look at:

MonthDay#PARSER

This is what finally helped me to find the correct solution. In any case, using the Builder you can construct whatever freaky non-standard parsers you want. Please however do remember to yell at everyone who thinks they can come up with yet another way of representing a date that needs to be unleashed into this world.

I hope this saves someone some heartache.

Artur

Edit: So once again I half ignored the question. I don't think there is a default way, unless you register a provider for yourself. However that seems a bit wrong to me. I think the way the parsing is meant to work is to have a static instance of your parser that you use. This is with regards to looking at how for example the default parsers in java time are implemented. So just create your custom parser at startup and reference it throughout your application for parsing.

like image 71
pandaadb Avatar answered Oct 17 '22 22:10

pandaadb