Comparing Date Strings in Java

How to compare two string dates in Java?

Convert them to an actual Date object, then call before.

SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd h:m");
System.out.println(sdf.parse(startDate).before(sdf.parse(endDate)));

Recall that parse will throw a ParseException, so you should either catch it in this code block, or declare it to be thrown as part of your method signature.

How to compare two dates in String format?

For a more generic approach, you can convert them both to Date objects of a defined format, and then use the appropriate methods:

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

Date date1 = format.parse(date1);
Date date2 = format.parse(date2);

if (date1.compareTo(date2) <= 0) {
System.out.println("earlier");
}

Comparing dates as strings in Java

Since your dates are in the YYYY-MM-DD format, a lexicographic comparison can be used to determine the ordering between two dates. Thus, you can just use the String.compareTo() method to compare the strings:

int c1 = objectDate.compareTo(dateOne);
int c2 = objectDate.compareTo(dateTwo);
if ((c1 >= 0 && c2 <= 0) || (c1 <= 0 && c2 >= 0)) {
// objectDate between dateOne and dateTwo (inclusive)
}

If it is guaranteed that dateOne < dateTwo, then you can just use (c1 >= 0 && c2 <= 0). To exclude the date bounds, use strict inequalities (> and <).

Comparing date strings in Java

I suggest you do the Right Thing (as described here) and convert to proper Date objects to compare. Worry about the performance impact if and when it actually impacts your application (which it probably won't).

Compare two date strings in different time zones with SimpleDateFormat in Java

tl;dr

OffsetDateTime
.parse( "2021-08-07T03:00:01-07:00" )
.isBefore(
OffsetDateTime.parse( "2021-08-07T15:30:00+05:30" )
)

See this code run live at IdeOne.com.

false

Details

As commented, your formatting pattern fails to match your data. You are not using correct codes for the offset-from-UTC at the end. That is not a time-of-day with the plus and minus signs.

Never use those terrible obsolete date-time classes. They were years ago supplanted by the modern java.time classes.

Your ISO 8601 standard inputs can be parsed by default using the OffsetDateTime classes. No need to define a formatting pattern.

String s1="2021-08-07T03:00:01-07:00";
String s2="2021-08-07T15:30:00+05:30";
OffsetDateTime odt1 = OffsetDateTime.parse( s1 ) ;
OffsetDateTime odt2 = OffsetDateTime.parse( s2 ) ;
boolean odt1IsEarlier = odt1.isBefore( odt2 ) ;

See this code run live at IdeOne.com.

You may choose to adjust both objects to UTC, having an offset of zero hours-minutes-seconds. Merely extract an Instant.

Instant i1 = odt1.toInstant() ;
Instant i2 = odt2.toInstant() ;

Comparing dates with months as strings

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.

Compare dates from a String in list

My solution would be:

    List<String> lista = List.of(
"Sevilla reserves himself to Apoel … sportyou 10/10/2019",
"I am new here 20/8/2019",
"A painting by Banksy … 19/10/2019");
List<String> sortedList = lista.stream()
.map(s -> new Object() {
String theString = s;
LocalDate date = extractDate(s);
})
.sorted(Comparator.comparing(obj -> obj.date))
.map(obj -> obj.theString)
.collect(Collectors.toList());
sortedList.forEach(System.out::println);

Output from this is:

I am new here 20/8/2019
Sevilla reserves himself to Apoel … sportyou 10/10/2019
A painting by Banksy … 19/10/2019

The extractDate method that I am using is:

private static Pattern datePattern = Pattern.compile("\\d{1,2}/\\d{1,2}/\\d{4}$");
private static DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("d/M/u");

private static LocalDate extractDate(String fullString) {
Matcher m = datePattern.matcher(fullString);
if (m.find()) {
String dateString = m.group();
return LocalDate.parse(dateString, dateFormatter);
} else {
throw new IllegalArgumentException("String doesn’t end with a date: " + fullString);
}
}

For efficient sorting of the strings — it only matters if there are many — I am extracting the trailing date and parsing it only once for each string (not for every comparison). I am parsing into LocalDate and use these for sorting. In order to get the original strings out after sorting I have put both the String and the LocalDate into an object and then sort these objects. It may surprise some that I can use an anonymous subclass of Object in this way, but it works nicely.

I recommend you don’t use SimpleDateFormat and Date. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead I am using LocalDate and DateTimeFormatter, both from java.time, the modern Java date and time API.

Java has nice sorting facilities built-in. If writing your own sorting algorithm was for an exercise, that’s a good exercise. Frankly you still had a way to go before your sorting would work. You may want to read up on sorting algorithms, there’s a lot written, also on the WWW. For production code you should rely on a library method.

Link: Oracle tutorial: Date Time explaining how to use java.time.

compare dates in String format

Is it really necessary to convert them to date and compare?

If you don't have to include timezones and can ensure that you always have this format the lexical order will work.

Will I miss anything?

You lose the flexibility

Am I doing the right thing?

That depends on the point of view. I use something similar in a specialized search-enginge (only for performance reasons). Usually I convert to Date and compare these objects.



Related Topics



Leave a reply



Submit