1

I am trying to compare these two dates :

17 Oct. 2019 (08:23)
19 déc. 2019 (21:15)

The months are in French and the main problem is the months. Do I need to put an if statement for every type of month so I can switch it with the appropriate month? For example:

if (MonthValue.equals("oct."){
    DateValue.replace("oct.","10");
}

Or is there an easier solution, because I need to check in a table if the first value is bigger than the second one.

Edit : My new Code :

String target1 = "17 oct. 2019 (08:23)";
        String target2 = "19 déc. 2019 (21:15)";
        DateFormat df = new SimpleDateFormat("dd MMM. YYYY (kk:mm)", Locale.FRENCH);
        Date result =  df.parse(target1);  
        Date result2 =  df.parse(target2); 
        System.out.println(result);
        System.out.println(result2);
        if(result.compareTo(result2) < 0) {
            System.out.println("true");
        }
        else {
            System.out.println("false");
        }

Doesn't work gives this error:

java.text.ParseException: Unparseable date: "17 oct. 2019 (08:23)"
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Yan
  • 108
  • 1
  • 8
  • 1
    Do you need to compare with String? why don't you parse to date and then compare it. – Gurkan İlleez Dec 06 '21 at 09:55
  • @Jelle The goal is clearly to compare 2 dates, what the reasoning behind that isn't really required by us. – Popeye Dec 06 '21 at 09:55
  • https://stackoverflow.com/questions/4496359/how-to-parse-date-string-to-date this will probably point you in the right direction. – Popeye Dec 06 '21 at 09:56
  • @Gurkanİlleez the goal is to compare two things either they both become date or they both become string but i want use string since with string i cant check if the first value is bigger than the second one – Yan Dec 06 '21 at 09:57
  • Look at Date.parseDate(). Also understand how locales work. – Kinjal Dixit Dec 06 '21 at 09:57
  • Does this answer your question? [How to parse date string to Date?](https://stackoverflow.com/questions/4496359/how-to-parse-date-string-to-date) – Popeye Dec 06 '21 at 09:58
  • @Popeye will it work for french too so my patern should be something like this String Pattern = " dd MMM. YYYY (kk:mm)" – Yan Dec 06 '21 at 10:00
  • Yes, you should be able to set Locale on it. – Popeye Dec 06 '21 at 10:01
  • 1
    @Popeye The solution you linked uses legacy classses though. It's highly recommended to use the Date & Time API introduced in Java SE 8. – Puce Dec 06 '21 at 10:05
  • @Popeye it's not working either way and i dont have the smallest idea about the reason – Yan Dec 06 '21 at 10:20
  • 1
    Has that string really got an upper case `O`in `Oct.`? That’s not usual where I read French. – Ole V.V. Dec 06 '21 at 11:06
  • 1
    I recommend you don’t use `SimpleDateFormat` and `Date`. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead use `LocalDateTime` and `DateTimeFormatter`, both from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Dec 06 '21 at 11:06
  • 1
    yeah that's what the answer uses @OleV.V. – Yan Dec 06 '21 at 11:07
  • I believe the comment by Ole V.V. refers to your use of uppercase “O” in your example data, `17 Oct. 2019 (08:23)`. In French cultures that I’ve seen, that should be `oct` rather than `Oct`. – Basil Bourque Dec 06 '21 at 14:21
  • I suggest you educate the publisher of your data about the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard. They should not be using localized text for exchanging date-time values. – Basil Bourque Dec 06 '21 at 14:25
  • @BasilBourque i wish i could but the one who did it quit and the new one cant change it since he doesnt know what it might change – Yan Dec 06 '21 at 14:41

5 Answers5

2

Using DateTimeFormatter with pattern dd MMM yyyy (HH:mm) to parse the date string like this

String target1 = "17 oct. 2019 (08:23)";
String target2 = "19 déc. 2019 (21:15)";

Locale locale = Locale.FRANCE;
DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder().appendPattern("dd MMM yyyy (HH:mm)")
        .toFormatter(locale);
LocalDateTime dateTime1 = LocalDateTime.parse(target1, dateTimeFormatter);
LocalDateTime dateTime2 = LocalDateTime.parse(target2, dateTimeFormatter);

System.out.println(dateTime1);
System.out.println(dateTime2);
if (dateTime1.compareTo(dateTime2) < 0) {
    System.out.println("true");
} else {
    System.out.println("false");
}
zephyr
  • 91
  • 4
  • Thank you it worked it seems that the . next to the MMM was the probleme if i am not wrong ? – Yan Dec 06 '21 at 10:27
  • @Yan Yes, the point is characters of the month itself – zephyr Dec 06 '21 at 10:32
  • 1
    Or without the builder: `DateTimeFormatter.ofPattern("dd MMM yyyy (HH:mm)", Locale.FRENCH)`. – MC Emperor Dec 06 '21 at 10:33
  • 1
    The main problem was the `.` which already is covered by `MMM` and especially `YYYY` which is the weekyear, `yyyy` is the normal year. On year change the week number can correspond to a (week-)year different of the actual year. – Joop Eggen Dec 06 '21 at 10:36
  • 1
    @Yan also the "oct." instead of "Oct." – matt Dec 06 '21 at 10:46
  • Fine suggestion. I would use `dateTime1.isBefore(dateTime2)` instead of `compareTo()`. – Ole V.V. Dec 06 '21 at 11:04
  • @zephyr another question please this format works for most of them by some months that doesnt go past 6 letters dont get parsed and crash the app is there a solution for this Ex: java.time.format.DateTimeParseException: Text '01 avril 2021 (09:40)' could not be parsed at index 3 – Yan Dec 06 '21 at 11:47
2

java.time and optional parts in the format pattern string

Like the others I recommend that you use java.time, the modern Java date and time API, for your date and time work. I understand that if your month names are five letters or shorter (for example avril), they are written out in full, whereas if they are seven letters or longer (for example juillet), they are abbreviated. The following formatter can parse in both situations:

private static final DateTimeFormatter DATE_FORMATTER
        = new DateTimeFormatterBuilder()
                .parseCaseInsensitive()
                .appendPattern("dd [MMMM][MMM] uuuu (HH:mm)")
                .toFormatter(Locale.FRENCH);    

Square brackets [] in the format pattern string surround optional parts. MMMM is for full month name. MMM is for the abbreviation. So the point in [MMMM][MMM] is that it will successfully parse either full month name or abbreviations and just skip the one that doesn’t work. Since you gave an example of Oct. being written with an upper case O, I have also specified that the parsing should not be sensitive to case. If this is not necessary, you may use this simpler formatter:

private static final DateTimeFormatter DATE_FORMATTER
        = DateTimeFormatter.ofPattern("dd [MMMM][MMM] uuuu (HH:mm)", Locale.FRENCH);

In order to check that all months work, I have set up these test data:

    String[] dateStrings = {
            "17 Oct. 2019 (08:23)",
            "19 déc. 2019 (21:15)",
            "01 avril 2021 (09:40)",
            "08 janv. 2020 (01:18)",
            "28 févr. 2021 (21:41)",
            "03 mars 2020 (22:54)",
            "06 mai 2020 (03:14)",
            "21 juin 2020 (07:15)",
            "18 juil. 2020 (23:06)",
            "06 août 2020 (22:28)",
            "29 sept. 2020 (06:04)",
            "18 nov. 2019 (01:35)"
    };

To parse and compare two of them use LocalDateTime.parse() and .isBefore():

    LocalDateTime dateTime1 = LocalDateTime.parse(dateStrings[1], DATE_FORMATTER);
    LocalDateTime dateTime2 = LocalDateTime.parse(dateStrings[2], DATE_FORMATTER);
    if (dateTime1.isBefore(dateTime2)) {
        System.out.format(Locale.FRENCH, "%s is before %s%n", dateTime1, dateTime2);
    }

Output:

2019-12-19T21:15 is before 2021-04-01T09:40

For comparison you may also exploit the fact that LocalDateTime implements Comparable. This is practical when sorting the dates and times, for example. As a brief example let’s sort all the LocalDateTime objects that come out of parsing the above strings:

    Arrays.stream(dateStrings)
            .map(ds -> LocalDateTime.parse(ds, DATE_FORMATTER))
            .sorted()
            .forEach(System.out::println);
2019-10-17T08:23
2019-11-18T01:35
2019-12-19T21:15
2020-01-08T01:18
2020-03-03T22:54
2020-05-06T03:14
2020-06-21T07:15
2020-07-18T23:06
2020-08-06T22:28
2020-09-29T06:04
2021-02-28T21:41
2021-04-01T09:40

Link: Trail: Date Time (The Java™ Tutorials) explaining how to use java.time.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
1

My recommendation:

Puce
  • 37,247
  • 13
  • 80
  • 152
  • doesnt work gives this error java.text.ParseException: Unparseable date: "17 oct. 2019 (08:23)" – Yan Dec 06 '21 at 10:08
  • @Yan parsing should work, the right Locale and format given (so it knows the month names, abbreviated). This is actually the best solution from both. – Joop Eggen Dec 06 '21 at 10:12
  • The method format(String, Object...) in the type String is not applicable for the arguments (DateTimeFormatter) i got this error after putting my pattern and my value – Yan Dec 06 '21 at 10:18
  • @Yan please update your question with what you've tried – Puce Dec 06 '21 at 10:24
0

What I've got from your question is that you want to convert Month's names to their respective numbers. If this is the case, then you should try switch
Example:

switch (MonthValue){
    case jan:
      MonthValue = 1; // Set Month variable to it Numbered Position (type casting might be required)
      break;
    case feb:
      MonthValue = 2;
      break;
    default:
      System.out.println("Somthing...");
}
  • 1
    i don't want to do this since if it will compare 1000 values it wan't be efficient – Yan Dec 06 '21 at 10:09
-1

Try encoding to UTF8, which will avoid DateTimeParseException Exception in thread "main" java.time.format.DateTimeParseException: Text '19 d??c. 2019 (21:15)' could not be parsed at index 3

    public static void main(String args[]) throws Exception {
        String date1 = "17 oct. 2019 (08:23)";
        String date2 = "19 déc. 2019 (21:15)";
        
        DateTimeFormatter longDateTimeFormatter = DateTimeFormatter.ofPattern("dd MMM yyyy (HH:mm)").withLocale(Locale.FRENCH);
        LocalDateTime lclDate1 = LocalDateTime.parse(encodeUTF8(date1), longDateTimeFormatter);
        LocalDateTime lclDate2 = LocalDateTime.parse(encodeUTF8(date2), longDateTimeFormatter);
        if (lclDate1.compareTo(lclDate2) < 0) {
            System.out.println("true");
        }
        else {
            System.out.println("false");
        }
    }
    
    public static String encodeUTF8(String dateStr) {
        byte[] bytes = dateStr.getBytes();
        String utf8EncodStr = new String(bytes, StandardCharsets.UTF_8);
        return utf8EncodStr;
    }
  • This is not correct. You're encoding the String to the platform default ecodiing, then decoding the bytes to back to a String using UTF_8. Odds are your platform default is UTF_8 so this is a non-op. – matt Dec 06 '21 at 10:48
  • 1
    And UTF-8 will be the [default across platforms](https://openjdk.java.net/jeps/400) in Java 18 and later. – Basil Bourque Dec 06 '21 at 14:16