Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.text.ParseException: Unparseable date : "..."

I get this error with this code:

SimpleDateFormat sdf = new SimpleDateFormat("EEEE dd MMMM HH:mm yyyy",myDateFormatSymbols);
sdf.parse("понеділок 12 квітень 07:00 2021");

Whis is "Monday 12 April 07:00 2021". The thing is, whenever I change the day from Monday to Tuesday ("вівторок"), I don't get this error, and the code works. Here's the code for myDateFormatSymbols:

private final static DateFormatSymbols myDateFormatSymbols = new DateFormatSymbols(){
        @Override
        public String[] getWeekdays(){
             return new String[]{"понеділок","вівторок", "середа", "четвер", "пятниця", "субота", "неділя"};
        }
        @Override
        public String[] getMonths() {
            return new String[]{...};
        }
}

All the months and weekdays are working correctly, seems that this error only occurs with Monday.

like image 878
k4rnaj1k Avatar asked Apr 09 '21 22:04

k4rnaj1k


People also ask

How do I fix Unparseable date error?

Try this: SimpleDateFormat in = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy"); in. setTimeZone(TimeZone. getTimeZone("Asia/Calcutta")); //or Asia/Jerusalem String s2 = "Fri Oct 23 11:07:08 IST 2015"; Date date = in.

What is ParseException in Java?

Class ParseExceptionSignals that an error has been reached unexpectedly while parsing. See Also: Exception , Format , FieldPosition , Serialized Form.


3 Answers

  • java.time

  • Standalone form of month name

  • DateTimeFormatterBuilder.appendText(TemporalField, Map<Long, String>)

I warmly recommend that you use java.time, the modern Java date and time API (links at the bottom), for your date and time work.

You are trying to parse a date-time string in Ukrainian. We would immediately have expected Java to do this out of the box using uk or uk-UA locale. Edit: To my surprise your strings are using what Java considers the standalone form of month names (it seems that I have not understood what the standalone form of a month name means). To specify this form in formatting use LLLL in the format pattern string rather than MMMM. Also the name of Friday in your strings is different from the name that Java knows (пʼятниця with an apostrophe, which, as Basil Bourque has already said, comes from CLDR). The solution is, as you already tried, to specify your own names of the days. In java.time this is done through a DateTimeFormatterBuilder and its two-arg appendText method. For example:

private static final Map<Long, String> DAY_NAMES = Map.of(1L, "понеділок", 2L, "вівторок",
        3L, "середа", 4L, "четвер", 5L, "пятниця", 6L, "субота", 7L, "неділя");
private static final Locale UKRAINIAN = Locale.forLanguageTag("uk-UA");
private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
        .appendText(ChronoField.DAY_OF_WEEK, DAY_NAMES)
        .appendPattern(" dd LLLL HH:mm uuuu")
        .toFormatter(UKRAINIAN);

Now with the formatter in place, parsing is trivial as it should be:

    String stringToParse = "понеділок 12 квітень 07:00 2021";
    LocalDateTime dateTime = LocalDateTime.parse(stringToParse, FORMATTER);
    System.out.println(dateTime);

Output:

2021-04-12T07:00

I find my code much clearer to read than yours, which is what counts for code. There are no funny overrides. There is no insane numbering of the months from 0. Monday is the first day of the week as it is in your question and in Ukraine.

Also java.time performs better validation by default. When your string says that April 12 is a Monday, java.time checks this and would have objected if it had not been the case.

Writing months in dates in Ukrainian (for other readers)

I knew nothing about writing dates in Ukrainian before writing this answer. For curious readers I would like to pass on a couple of observations from my searches.

Two forms of month names seem to be used:

  1. The nominative, which Java knows as the standalone form, for example січень for January. This form often ends in -ень (-en).
  2. The genitive, which Java uses as the normal (non-standalone) form, for example січня for January. Possibly “of January” could be used as a translation? This form often ends in -ня (-nya?)

In the Internet I have seen both forms used in dates. I am not very sure, but possibly the trends are: The nominative (standalone) form is used when no day of month is present and sometimes informally when one is; the genitive is used formally when day of month is present.

Links

  • Java SE 8 Date and Time: Why do we need a new date and time library?
  • Oracle tutorial: Date Time explaining how to use java.time.
  • How to Write Dates in Ukrainian + Useful Time Expressions (which, if I understand correctly, recommends against using the standalone form in dates)
like image 167
Ole V.V. Avatar answered Oct 06 '22 11:10

Ole V.V.


java.time

The Answer by Hajaj looks correct. But the Question and that Answer both use terrible date-time classes that were years ago supplanted by the modern java.time classes defined in JSR 310.

Trying original input given in Question.

String input = "понеділок 12 квітень 07:00 2021";
Locale locale = new Locale.Builder().setLanguage( "uk" ).setRegion( "UA" ).build();
DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEEE dd MMMM HH:mm yyyy" ).withLocale( locale );
LocalDateTime ldt = LocalDateTime.parse( input , f );
System.out.println( "ldt = " + ldt );

See that code run live at IdeOne.com, using Java 12.

With your input I get a DateTimeParseException saying "Text 'понеділок 12 квітень 07:00 2021' could not be parsed at index 13". That means a problem with your month name.

Incorrect month name?

I know nothing about the Ukrainian language. So as an experiment, I tried the opposite, generating text rather than parsing text. I get a different variation on the month name.

Locale locale = new Locale.Builder().setLanguage( "uk" ).setRegion( "UA" ).build();
DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEEE dd MMMM HH:mm yyyy" ).withLocale( locale );

LocalDateTime ldt = LocalDateTime.of( 2021 , Month.APRIL , 12 , 7 , 0 );
String output = ldt.format( f );
LocalDateTime ldt2 = LocalDateTime.parse( output , f );

System.out.println( "ldt.toString() = " + ldt );
System.out.println( "output = " + output );
System.out.println( "ldt2.toString() = " + ldt2 );

See this code run live at IdeOne.com.

Results:

ldt.toString() = 2021-04-12T07:00
output = понеділок 12 квітня 07:00 2021
ldt2.toString() = 2021-04-12T07:00

So the publisher of your data is using a variation of the month name not expected by the current locale definitions used by Java. The primary default set of locale definitions used by modern Java (Java 9 and later in general, and Java 16 here for me) is the Unicode Common Locale Data Repository (CLDR). The fallback definitions may be an obsolete Java-specific set that was bundled as the primary set in older versions of Java. I do not know which set of locale definitions is in play here, but I think it is a safe bet to say the CLDR has Ukrainian covered and therefore must be in play here.

As I said, I do not know Ukrainian. But I suspect your input’s month name is not correct linguistically/grammatically/spelling-wise.

like image 3
Basil Bourque Avatar answered Oct 06 '22 12:10

Basil Bourque


You can check the Javadoc for DateFormatSymbols#weekdays, the element at index 0 is always ignored unfortunately.

I'd simply replace it by an empty string.

Weekday strings. For example: "Sunday", "Monday", etc. An array of 8 strings, indexed by Calendar.SUNDAY, Calendar.MONDAY, etc. The element weekdays[0] is ignored.


The following code now prints the expected answer

DateFormatSymbols myDateFormatSymbols = new DateFormatSymbols() {
    @Override
    public String[] getWeekdays() {
        return new String[]{"", "понеділок", "вівторок", "середа", "четвер", "пятниця", "субота", "неділя"};
    }

    @Override
    public String[] getMonths() {
        return new String[]{"квітень"};
    }
};

SimpleDateFormat sdf = new SimpleDateFormat("EEEE dd MMMM HH:mm yyyy", myDateFormatSymbols);
System.out.println(sdf.parse("понеділок 12 квітень 07:00 2021")); // Tue Jan 12 07:00:00 CET 2021
like image 2
Yassin Hajaj Avatar answered Oct 06 '22 11:10

Yassin Hajaj