How can I set date and time formatting in Java that respects the user's OS settings

Viewed 11781

I am running my Java app on a Windows 7 machine where my regional settings are set up to format dates as YYYY-mm-dd and time as HH:mm:ss (e.g. "2011-06-20 07:50:28"). But when I use DateFormat.getDateTimeInstance().format to format my date I do not see that instead I get "20-Jun-2011 7:50:28 AM". What do I need to do to format dates in the way that my customers have their OS setup to display dates?

Here is what my code in question looks like:

File selGameLastTurnFile = selectedGame.getLastTurn ().getTurnFile ();
Date selGameModifiedDate = new Date (selGameLastTurnFile.lastModified());
if (selectedGame.isYourTurn ())  {
    gameInfo = Messages.getFormattedString ("WhoseTurnIsIt.Prompt.PlayTurn",  //$NON-NLS-1$
            FileHelper.getFileName (selGameLastTurnFile), 
            DateFormat.getDateTimeInstance().format(selGameModifiedDate));
}  else  {
    gameInfo = Messages.getFormattedString ("WhoseTurnIsIt.Prompt.SentTurn",  //$NON-NLS-1$
            selGameLastTurnFile.getName (), 
            DateFormat.getDateTimeInstance().format(selGameModifiedDate));
}

The Messages.getFormattedString calls are using MessageFormat to put the date into a sentence that will look like this:

Play the turn 'QB Nat vs Ian 008' (received 20-Jun-2011 7:50:28 AM)

However my OS settings are setup to format the date as I described above and I expected to see this:

Play the turn 'QB Nat vs Ian 008' (received 2011-06-20 07:50:28)

I searched here and other Java programming sites and could not find the answer but this seems like such an obvious thing to want to do that I feel like I am missing something obvious.

7 Answers

Oracle JDK 8 fully supports formatting using user-customized OS regional settings.

Just set system property java.locale.providers=HOST

According to https://docs.oracle.com/javase/8/docs/technotes/guides/intl/enhancements.8.html:

HOST represents the current user's customization of the underlying operating system's settings. It works only with the user's default locale, and the customizable settings may vary depending on the OS, but primarily Date, Time, Number, and Currency formats are supported.

The actual implementation of this formatter is available in the class sun.util.locale.provider.HostLocaleProviderAdapterImpl. If using system property is not acceptable (say, your don't want to affect the whole application), it's possible to use that provider class directly. The class is internal API, but can be reached using reflection:

private static DateFormat getSystemDateFormat() throws ReflectiveOperationException {
        Class<?> clazz = Class.forName("sun.util.locale.provider.HostLocaleProviderAdapterImpl");
        Method method = clazz.getMethod("getDateFormatProvider");
        DateFormatProvider dateFormatProvider = (DateFormatProvider)method.invoke(null);
        DateFormat dateFormat = dateFormatProvider.getDateInstance(DateFormat.MEDIUM, Locale.getDefault(Locale.Category.FORMAT));
        return dateFormat;
    }
java -Djava.locale.providers=HOST,CLDR,COMPAT YourProgram

Date and time formats are part of Java’s locale data. Java can get its locale data from up to four sources. Which ones it uses is controlled by the java.locale.providers system property. Default up to Java 8 was JRE,SPI. From Java 9 it’s CLDR,COMPAT. None of these will get you the date and time data from the operating system, but you can get them by supplying the HOST locale provider, for example as in the command line above. When running your program with this property definition, you may for example have:

    DateTimeFormatter systemFormatter
            = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL);
    ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Africa/Bangui"));
    String formattedDateTime = now.format(systemFormatter);
    System.out.println(formattedDateTime);

This will print the current date and time in the format defined by the underlying operating system. To the extend that the operating system supports it you can vary the length of the output by using format styles FULL, LONG, MEDIUM and SHORT.

For most purposes you will want to have a DateTimeFormatter knowing the format as in the above code. In the rare case where you want to know a format pattern string that is possible too:

    String osFormat = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
            FormatStyle.SHORT, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.getDefault());

The first argument to getLocalizedDateTimePattern is the date format style. The second is the time style.

Related