0

I have this trash DateFormat in a log file that need to parse in order to compare it.

It’s in this format. Mon 03-Mai-21

My try:

    DateFormat format = new SimpleDateFormat("EEE FF-MMM-YY", Locale.GERMAN);
    String test = "Mon 03-Mai-21";
    Date date = null;
    try {
        date = format.parse(test);
    } catch (ParseException e) {
        e.printStackTrace();
    }

I’m getting a ParseException when trying to parse, but I have no clue what’s wrong with my pattern?

My expected result is 2021-05-03.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Dahlin
  • 157
  • 1
  • 11
  • Don’t ever use `SimpleDateFormat` and `Date`. They are so poorly designed, so cumbersome and error-prone to work with and so long outdated. Use `DateTimeFormatter` and `LocalDate` from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/index.html). And enjoy. – Ole V.V. Nov 10 '21 at 16:17
  • What is your expected result? 2021-05-17? 2021-05-03? Or? – Ole V.V. Nov 10 '21 at 16:27
  • 1
    okay I will try that, 2021-05-03 it is – Dahlin Nov 10 '21 at 16:34
  • Thank you, danke schön. Two points for your future questions: (1) when asking about code that doesn’t work, always state the expected/desired behaviour. Even when, as here, it looked like it was obvious. (2) When providing more information (which is often necessary and always welcome), edit the question so we have everything in one place. Many readers don’t come around to reading the comments. – Ole V.V. Nov 10 '21 at 17:10

1 Answers1

2

java.time

I recommend that you use java.time, the modern Java date and time API, for your date work.

Declare a formatter for your format:

private static Map<Long, String> dayOfWeekAbbreviations
        = Map.ofEntries(
                Map.entry(1L, "Mon"),
                Map.entry(2L, "Die"),
                Map.entry(3L, "Mit"),
                Map.entry(4L, "Don"),
                Map.entry(5L, "Fre"),
                Map.entry(6L, "Sam"),
                Map.entry(7L, "Son"));

private static final DateTimeFormatter DATE_FORMATTER
        = new DateTimeFormatterBuilder()
                .appendText(ChronoField.DAY_OF_WEEK, dayOfWeekAbbreviations)
                .appendPattern(" dd-MMM-uu")
                .toFormatter(Locale.GERMAN);    

Parse like this:

    String test = "Mon 03-Mai-21";
    LocalDate date = LocalDate.parse(test, DATE_FORMATTER);
    System.out.println(date);

Output:

2021-05-03

Java assumes that the days of the week are abbreviated Mo., Di., Mi., Do., Fr., Sa., So. (at least my Java 11 does; I think there are Java version where the abbreviations come without the dots by default). Since your abbreviation was Mon for Montag (Monday), we needed to provide our own abbreviations. This is what I do through the map. I don’t know which abbreviations you are getting for the other days of the week, so please fill the right ones into the map yourself.

The other possible solution of course is to make sure the strings you are getting use Java’s abbreviations. Then you can use EEE in your format pattern string as in your question, which would make the formatter somewhat simpler.

What went wrong in your code?

There are three issues with what you tried:

  1. As I said, EEE in your format pattern string expects a two-letter day-of-week abbreviation like Mo. so cannot accept Mon. This caused the exception you saw.
  2. FF is for the “day of week in month”. So you were really trying to parse your string as the 3rd Monday of May 2021, which was why I asked whether you expected 17th of May. Lower case dd is for day of month.
  3. Upper case YY for year is wrong. Upper case Y is for week-based year and only useful with a week number. For year you would need lower case y with SimpleDateFormat. With DateTimeFormatter you may use u or y with a different meaning for years before year 1.

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • 2
    very strange, `java.time.DateTimeFormatter` has a different interpretation of `F` - it just gives back the weekday as number (e.g. it returns `1` for `2021-11-22`; while `SimpleDateFormat` returns `4`) [IDEone](https://ideone.com/VC39D6) – user16320675 Nov 10 '21 at 18:44
  • @user16320675 The pattern letters are inspired from Unicode but with some variation. For `F` [the standard](https://unicode.org/reports/tr35/tr35-dates.html#Contents) says *Day of Week in Month (numeric). The example (2) is for the 2nd Wed in July*. The way I read the docs both `SimpleDateFormat` and `DateTImeFormatter` follow this faithfully. I will do some experiments. – Ole V.V. Nov 10 '21 at 19:04
  • Really!! @user16320675 The Java 8 documentation of `DateTimeFormatter` says that `F` is week-of-month. In Java 11 the documentation is changed to day-of-week-in-month (in agreement with Unicode), but you are right, it still seems to produce the day number of the aligned week of the month: 1 on the 1st of the month, 2 on 2nd through 7 on 7th, then 1 on 8th, etc. Is it a bug? – Ole V.V. Nov 10 '21 at 19:33
  • Their understanding of what *day-of-week-in-month* means neither agrees with Unicode nor with `SimpleDateFormat`. They may have fixed it the way they wanted to, but I still call it a bug. @user16320675 – Ole V.V. Nov 10 '21 at 19:41
  • 1
    agreed. The `DateTimeFormatter` implementation is kind of useless, basically day-of-month modulo 7 - the `SimpleDateFormat` / Unicode definition is more *powerful* (like having an event every second Monday of a month) – user16320675 Nov 10 '21 at 20:07
  • I tried implementing your solution, works perfectly, thanks! – Dahlin Nov 11 '21 at 13:56