SimpleDateFormat pattern based on locale, but forcing a 4-digit year

17,029

Solution 1

I would do it like this:

    StringBuffer buffer = new StringBuffer();

    Calendar date = Calendar.getInstance();
    DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
    FieldPosition yearPosition = new FieldPosition(DateFormat.YEAR_FIELD);

    StringBuffer format = dateFormat.format(date.getTime(), buffer, yearPosition);
    format.replace(yearPosition.getBeginIndex(), yearPosition.getEndIndex(), String.valueOf(date.get(Calendar.YEAR)));

    System.out.println(format);

Using a FieldPosition you don't really have to care about wheter the format of the date includes the year as "yy" or "yyyy", where the year ends up or even which kind of separators are used.

You just use the begin and end index of the year field and always replace it with the 4 digit year value and that's it.

Solution 2

java.time

Here’s the modern answer. IMHO these days no one should struggle with the long outdated DateFormat and SimpleDateFormat classes. Their replacement came out in the modern Java date & time API early in 2014, the java.time classes.

I am just applying the idea from Happier’s answer to the modern classes.

The DateTimeFormatterBuilder.getLocalizedDateTimePattern method generates a formatting pattern for date and time styles for a Locale. We manipulate the resulting pattern string to force the 4-digit year.

LocalDate date = LocalDate.of( 2017, Month.JULY, 18 );

String formatPattern =
    DateTimeFormatterBuilder.getLocalizedDateTimePattern(
        FormatStyle.SHORT, 
        null, 
        IsoChronology.INSTANCE, 
        userLocale);
formatPattern = formatPattern.replaceAll("\\byy\\b", "yyyy");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatPattern, userLocale);

String output = date.format(formatter);

Example output:

  • For Locale.US: 7/18/2017.
  • For each of UK, FRANCE, GERMANY and ITALY: 18/07/2017.

DateTimeFormatterBuilder allows us to get the localized format pattern string directly, without getting a formatter first, that’s convenient here. The first argument to getLocalizedDateTimePattern() is the date format style. null as second argument indicates that we don’t want any time format included. In my test I used a LocalDate for date, but the code should work for the other modern date types too (LocalDateTime, OffsetDateTime and ZonedDateTime).

Share:
17,029

Related videos on Youtube

lili
Author by

lili

Updated on June 04, 2022

Comments

  • lili
    lili almost 2 years

    I need to build a date format like dd/MM/yyyy. It's almost like DateFormat.SHORT, but contains 4 year digits.

    I try to implement it with

    new SimpleDateFormat("dd//MM/yyyy", locale).format(date);
    

    However for US locale the format is wrong.

    Is there a common way to format date that changes pattern based on locale?

    Thank you

  • jarnbjo
    jarnbjo over 12 years
    No, he wanted a localized DateFormat.SHORT pattern with a four digit year.
  • Andrew Norman
    Andrew Norman over 12 years
    Right, I misread some of my code. In that case ... do that above (after replacing LONG with SHORT) ... then call toPattern() after casting the DateFormat to SimpleDateFormat and then search and replace the yy to yyyy. Then create a new SimpleDateFormat with the new string pattern.
  • jarnbjo
    jarnbjo over 12 years
    Still wrong. You cannot expect the instance returned by DateFormat.getDateInstance to be of the type SimpleDateFormat.
  • Andrew Norman
    Andrew Norman over 12 years
    Thats wierd ... because the javadoc states "You can also set the time zone on the format if you wish. If you want even more control over the format or parsing, (or want to give your users more control), you can try casting the DateFormat you get from the factory methods to a SimpleDateFormat. This will work for the majority of countries; just remember to put it in a try block in case you encounter an unusual one."
  • jarnbjo
    jarnbjo over 12 years
    What didn't you understand of "you can try ..." and "work for the majority ..."?
  • Andrew Norman
    Andrew Norman over 12 years
    Have a look at the code in the DateFormat class ... EVERY available locale that is shipped with Java 6 returns a SimpleDateFormat instance. Yes it will cause a problem if you define your own locale and return an instance other than SimpleDateFormat .. but generally it will work.