Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DateTimeFormatter not work with LLLL pattern in en locale

With ru locale return full month name (Февраль), but with en only number(2).

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("LLLL", new Locale("ru"));
LocalDate.now().format(formatter);

MMMM work with en, but not work with ru (need nominative case).

How get full month name for all locales?

like image 871
Nick Avatar asked Feb 15 '17 09:02

Nick


1 Answers

Unfortunately the related bug issue JDK-8114833 has not yet been solved for Java-8. And it is not yet clear for me if Java-9 offers a solution (and there the feature-freeze-date is already over). So you can either apply following workaround based on your knowledge which languages need a special standalone-form (nominative) for months and which not:

private static final Set<String> LANGUAGES_WITH_STANDALONE_CASE;

static {
    Set<String> set = new HashSet<>();
    set.add("ru");

    // add more languages which require LLLL-pattern (for example other slavish languages)
    LANGUAGES_WITH_STANDALONE_CASE = Collections.unmodifiableSet(set);
}

public static void main(String[] args) throws Exception {

    Locale locale = new Locale("en");

    DateTimeFormatter formatter =
      DateTimeFormatter.ofPattern(
        LANGUAGES_WITH_STANDALONE_CASE.contains(locale.getLanguage()) 
          ? "LLLL" : "MMMM",
        locale
      );
    System.out.println(LocalDate.now().format(formatter));

    // ru => Февраль
    // en => February
}

I cannot say that I like this solution because it requires extra knowledge which languages need which pattern. But it is actually the only possibility to solve your problem within the scope of JSR-310 (aka java.time-API).

By testing I see now that even the old class SimpleDateFormat (version in Java-8) works:

    Locale locale = new Locale("en");

    SimpleDateFormat sdf = new SimpleDateFormat("LLLL", locale);
    System.out.println(sdf.format(new Date()));

But that workaround has the strong disadvantage not to work with a plain calendar date but with java.util.Date only.

Or you might be willing to add an extra dependency to a library which has better support for the pattern letter "L" AND has better API-style AND better performance characteristics. For example you could use my library Time4J. Here a demonstration of latter case which also shows how the independent format engine of Time4J can be used for the JSR-310-types (also in parsing):

    Locale locale = new Locale("ru");

    ChronoFormatter<LocalDate> formatter =
        ChronoFormatter.ofPattern(
            "LLLL",
            PatternType.CLDR,
            locale,
            PlainDate.axis(TemporalType.LOCAL_DATE)
        );
    System.out.println(formatter.format(LocalDate.now()));

    // ru => Февраль
    // en => February

For best performance, I recommend to lazily store the formatter in a ConcurrentHashMap per locale.

like image 150
Meno Hochschild Avatar answered Oct 15 '22 16:10

Meno Hochschild