10

I need to format incomplete date only to month precision. My first guess was to apply pattern "MMMM yyyy" to it. This works fine for many locales (English, German, ...), but gives ugly result for languages with flexion, e.g. Russian. I read documentation of SimpleDateFormat and found that 'L' is supposed to give context-insensitive month name: just what I need, as there is no day of month in the pattern. So I tried pattern "LLLL yyyy" instead. It works perfectly for Russian and other flexion languages, but instead fails for e.g. English and German...

Here is the test code:

import java.text.*;
import java.util.*;

public class test
{
    public static void main (String[] arguments) throws Exception
    {
        for (String locale : new String[] { "en", "de", "hu", "it", "ru", "fi", "pl" })
            System.out.format ("%s: %s \t%s\n", locale,
                               new SimpleDateFormat ("MMMM yyyy", new Locale (locale)).format (new Date ()),
                               new SimpleDateFormat ("LLLL yyyy", new Locale (locale)).format (new Date ()));
    }
}

And its output:

en: September 2015      0009 2015
de: September 2015      0009 2015
hu: szeptember 2015     szeptember 2015
it: settembre 2015      Settembre 2015
ru: сентября 2015       Сентябрь 2015
fi: syyskuuta 2015      syyskuu 2015
pl: września 2015       wrzesień 2015

So, for the tested locales: 'en' and 'de' work properly only with 'M', 'hu' is fine with both 'M' and 'L', 'it' is probably better off with 'L' (don't know how important capital letter is here), while 'ru', 'fi' and 'pl' give correct output only with 'L' (this I can really tell only for Russian and Polish, but I presume it's similar in Finnish).

Questions:

  • Can I do something to make SimpleDateFormat or a similar date formatting class treat 'L' properly for all locales?

  • Alternatively, is there a simple way to tell if 'M' or 'L' should be used for any given locale?

  • I don't speak russian but are you saying that `M` identifier gives an incorrect month name? What's the difference in meaning between 'сентября' and 'Сентябрь'? – Tunaki Sep 29 '15 at 09:27
  • 2
    Same as in Finnish. The month's name is syyskuu. But if there is a day mentioned it has to be: 15. syyskuuta (that is the meaning of standalone form vs. context sensitive). – Würgspaß Sep 29 '15 at 09:30
  • 1
    Which version of Java 8 are you using? The `L` was introduced only in Java 8, and on my machine your program produces "September" for `en` and `de` as well. Perhaps you have a version with outdated locale files? – RealSkeptic Sep 29 '15 at 09:38
  • @RealSkeptic: That sounds plausible. 1.8.0_40 here. –  Sep 29 '15 at 09:39
  • I'm with JDK 1.8.0_51 and I have the same result as the OP – Tunaki Sep 29 '15 at 09:40
  • Mine is 1.8.0_60, tested on both Mac and Linux. – RealSkeptic Sep 29 '15 at 09:41
  • @RealSkeptic: Aha, thank you. I'll see if upgrading our production machines is feasible. –  Sep 29 '15 at 09:42
  • 2
    JDK bug: https://bugs.openjdk.java.net/browse/JDK-8114833 (it is for DateTimeFormatter but I guess it's the same for SimpleDateFormat) – Tunaki Sep 29 '15 at 09:42

2 Answers2

4

It is an official bug - JDK-8075548

The bug is in status "resolved", and you can see that the fix has been backported to versions 8_60 and 8_65, but not earlier versions of Java 8.

Therefore, the proper solution, if possible, is to upgrade to Java 1.8.0_60.

RealSkeptic
  • 33,993
  • 7
  • 53
  • 79
1

java.time

The SimpleDateFormat class is part of the troublesome old date-time classes that are now legacy, supplanted by the java.time classes.

In java.time, the formatting pattern codes are similar to the old ones but next exactly the same. Be sure to study class doc for DateTimeFormatter.

final DateTimeFormatter fCombo = DateTimeFormatter.ofPattern ( "MMMM uuuu" );
final DateTimeFormatter fStandalone = DateTimeFormatter.ofPattern ( "LLLL uuuu" );

final LocalDate localDate = LocalDate.now ( ZoneId.of ( "America/Montreal" ) );
for ( final String locale : new String[] { "en" ,  "fr" , "de" , "hu" , "it" , "ru" , "fi" , "pl" } ) {
    final Locale l = new Locale ( locale );

    System.out.format (
            "%s: %s | %s\n",
            locale,
            localDate.format ( fCombo.withLocale ( l ) ),
            localDate.format ( fStandalone.withLocale ( l ) )
    );
}

en: March 2017 | 3 2017

fr: mars 2017 | 3 2017

de: März 2017 | 3 2017

hu: március 2017 | március 2017

it: marzo 2017 | Marzo 2017

ru: марта 2017 | Март 2017

fi: maaliskuuta 2017 | maaliskuu 2017

pl: marca 2017 | marzec 2017


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154