SimpleDateFormat - format - Month September - JDK16

3.6k views Asked by At

I have just upgraded Java from JDK-15 to JDK-16 and I see a problem while converting Date using SimpleDateFormat. September month alone while formatted using yyyy-MMM-dd is giving 4 characters instead of 3.

Eg: 2021-Sep-11 is being shown as 2021-Sept-11

    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.DATE, 150);
    SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MMM-dd");
    System.out.println(cal.getTime());

    String formatted = format1.format(cal.getTime());
    System.out.println(formatted);

Looks like a bug to me. I can't see any update to this in the release notes. Anyone facing similar issue? Was working alright till JDK-15.

2

There are 2 answers

0
Arvind Kumar Avinash On BEST ANSWER

Never use Date-Time formatting/parsing type without Locale because the texts are Locale-sensitive.

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, 150);
        SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MMM-dd", Locale.ENGLISH);
        System.out.println(cal.getTime());

        String formatted = format1.format(cal.getTime());
        System.out.println(formatted);
    }
}

Output:

2021-Sep-11

Note that the java.util date-time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to java.time, the modern date-time API* .

Using modern date-time API:

import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        // Change ZoneId as per your requirement e.g. ZoneId.of("Europe/London")
        LocalDate date = LocalDate.now(ZoneId.systemDefault());
        date = date.plusDays(150);
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MMM-dd", Locale.ENGLISH);
        String formatted = dtf.format(date);
        System.out.println(formatted);
    }
}

Output:

2021-Sep-11

Check this answer to learn more about u vs y.

Learn more about the modern date-time API from Trail: Date Time.


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

0
Dave The Dane On

Here's a version of that that will stay in September:

final Calendar cal = Calendar.getInstance();
/**/           cal.set(2021, Calendar.SEPTEMBER, 11, 23, 59, 59);

final String           pattern = "yyyy-MMM-dd LL LLL EEE EEEE";
final SimpleDateFormat format1 = new SimpleDateFormat(pattern);

System.out.println("Locale..: " + Locale.getDefault());
System.out.println("Calendar: " + cal.getTime());
System.out.println("Pattern.: " + pattern + " -> " + format1.format(cal.getTime()));

System.out.println("Vendor..: " + ManagementFactory.getRuntimeMXBean().getVmVendor());
System.out.println("VM......: " + ManagementFactory.getRuntimeMXBean().getVmName());
System.out.println("Version.: " + ManagementFactory.getRuntimeMXBean().getSpecVersion());
System.out.println("Build...: " + ManagementFactory.getRuntimeMXBean().getVmVersion());

On a German system it produces the following Outputs for me:

Locale..: de_DE
Calendar: Sat Sep 11 23:59:59 CEST 2021
Pattern.: yyyy-MMM-dd LL LLL EEE EEEE -> 2021-Sept.-11 09 Sep Sa. Samstag
Vendor..: Oracle Corporation
VM......: Java HotSpot(TM) 64-Bit Server VM
Version.: 16
Build...: 16+36-2231

and

Locale..: de_DE
Calendar: Sat Sep 11 23:59:59 CEST 2021
Pattern.: yyyy-MMM-dd LL LLL EEE EEEE -> 2021-Sep-11 09 Sep Sa Samstag
Vendor..: Oracle Corporation
VM......: Java HotSpot(TM) 64-Bit Server VM
Version.: 1.8
Build...: 25.40-b25

Here too, SimpleDateFormat produced different formattings for the Month, but the Spec. is a little vague. It says:

"Month: If the number of pattern letters is 3 or more, the month is interpreted as text"

So far so good, but it qualifies "text" as follows...

"Text: For formatting, if the number of pattern letters is 4 or more,the full form is used; otherwise a short or abbreviated form is used if available."

But for our example, with 3 pattern lettters, quite what that short form is is not clear.

But maybe "L" will help with the Month name?