Unable to Parse a date of format d MMMM yyyy in Polish Locale in Java

1.2k views Asked by At

I tried to parse the date (3 December, 2020) with format d MMMM yyyy in Polish Locale but it is unable to parse. But why the same parsing is working fine in any other locale like english, etc. Below is the code sample which is not working. Can anyone please help on this ?

    Locale loc = new Locale("pl", "PL");
    String date = "3 December 2020";
    SimpleDateFormat sdFormat =
            new SimpleDateFormat("d MMMM yyyy", loc);
    sdFormat.setLenient(false);
    try {
        Date d = sdFormat.parse(date);
        System.out.println(d);
    } catch (ParseException e) {
        e.printStackTrace();
    }
2

There are 2 answers

0
Arvind Kumar Avinash On BEST ANSWER

It seems you got confused with parsing and formatting.

Since your input date string in English, you need to use Locale.ENGLISH for parsing and you need another instance of SimpleDateFormat with Locale("pl", "PL") to format the obtained java.util.Date object with new Locale("pl", "PL").

Demo:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class Main {
    public static void main(String args[]) {
        Locale loc = new Locale("pl", "PL");
        String date = "3 December 2020";
        SimpleDateFormat sdfForParsing = new SimpleDateFormat("d MMMM yyyy", Locale.ENGLISH);
        SimpleDateFormat sdfForFormatting = new SimpleDateFormat("d MMMM yyyy", loc);
        sdfForParsing.setLenient(false);
        try {
            Date d = sdfForParsing.parse(date);
            System.out.println(d);
            String localiseByPolish = sdfForFormatting.format(d);
            System.out.println(localiseByPolish);

        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

Output:

Thu Dec 03 00:00:00 GMT 2020
3 grudnia 2020

I believe you already know that a date-time object stores just the date-time information*1and no formatting information. On printing, a date-time object prints the string returned by the toString implementation of its class. Also, a java.util.Date object does not represent a true date-time class as it stores just the milliseconds (e.g. new Date() object is instantiated with the number of milliseconds from January 1, 1970, 00:00:00 GMT) and when you print it, it calculates the date-time in your JVM's timezone and prints the same i.e. if your execute the following two lines at a given moment in any part of the world,

Date date = new Date();
System.out.println(date.getTime());

you will get the same number. Check this answer for a demo.

The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and because of so many such hacks, they are error-prone. It is recommended to stop using them completely and switch to the modern date-time API. Learn more about the modern date-time API at Trail: Date Time.

Note: 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.

Using the modern date-time API:

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

public class Main {
    public static void main(String args[]) {
        Locale loc = new Locale("pl", "PL");
        String date = "3 December 2020";
        DateTimeFormatter dtfForParsing = DateTimeFormatter.ofPattern("d MMMM yyyy", Locale.ENGLISH)
                                            .withResolverStyle(ResolverStyle.LENIENT);
        DateTimeFormatter dtfForFormatting = DateTimeFormatter.ofPattern("d MMMM yyyy", loc);
        LocalDate localeDate = LocalDate.parse(date, dtfForParsing);
        System.out.println(localeDate);
        String localiseByPolish = localeDate.format(dtfForFormatting);
        System.out.println(localiseByPolish);
    }
}

Output:

2020-12-03
3 grudnia 2020

*1The modern date-time API store also the timezone information. Check Overview to learn more about these classes.

2
Andreas On

When trying to determine problems with parsing, always do the opposite, i.e. generate output, to see what the input for parsing should look like. This is a technique that is very useful for all parsing related issues, whether parsing date strings, XML documents, JSON texts, etc.

So, we try printing a date value with the given format, to see what it would expect when parsing:

Locale loc = new Locale("pl", "PL");
SimpleDateFormat sdFormat = new SimpleDateFormat("d MMMM yyyy", loc);
sdFormat.setLenient(false);

Calendar cal = Calendar.getInstance(loc);
cal.clear();
cal.set(2020, Calendar.DECEMBER, 3);
System.out.println(sdFormat.format(cal.getTime()));

In Java 7, I get 3 grudzień 2020.
In Java 8, 9, 11, and 14, I get 3 grudnia 2020.

If you want to parse 3 December 2020, then use e.g. Locale.ENGLISH.