Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

When dealing with datasets that contain date times in string format, sorting those strings is a common task in many Java applications.

In this tutorial, we’ll explore different approaches to effectively sorting date strings in Java.

2. Introduction to the Problem

We can directly sort strings lexicographically in specific date formats, such as the ISO date time format (YYYY-MM-dd’T’ HH:mm:ss). However, this isn’t a general solution for sorting date strings.

We cannot apply a lexicographically-sorting operation on all date-time formats. For example, let’s say we have such a list of strings:

List<String> dtStrings = Lists.newArrayList(
  "01/21/2013 10:41",
  "01/20/2013 10:48",
  "01/22/2013 15:13",
  "01/21/2013 16:37",
  "01/21/2013 17:16",
  "01/21/2013 17:19",
  "01/20/2013 06:16",
  "01/22/2013 06:19"
);

If the strings in the list are sorted correctly, the result should look like this:

List<String> EXPECTED = Lists.newArrayList(
  "01/20/2013 06:16",
  "01/20/2013 10:48",
  "01/21/2013 10:41",
  "01/21/2013 16:37",
  "01/21/2013 17:16",
  "01/21/2013 17:19",
  "01/22/2013 06:19",
  "01/22/2013 15:13"
);

We’ll explore different approaches to solving the sorting problem. Also, for simplicity, we’ll use unit test assertions to verify whether each solution produces the expected result.

Next, let’s see them in action.

3. Using a Custom Comparator

The Java standard library provides the Collections.sort() method to sort elements in a collection. If we want to sort a list of strings in lexicographic order, we can simply pass the list to the Collections.sort() method. Further, the method accepts a Comparator object as the second argument too.

Next, let’s see how to sort date-time strings using a custom Comparator:

DateFormat dfm = new SimpleDateFormat("MM/dd/yyyy HH:mm");
Collections.sort(dtStrings, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        try {
            return dfm.parse(o1).compareTo(dfm.parse(o2));
        } catch (ParseException e) {
            throw new IllegalArgumentException(e);
        }
    }
});
assertEquals(EXPECTED, dtStrings);

As the code above shows, first, we created a SimpleDateFormat object according to the date string format. Then, when we call the Collections.sort() method, we pass the dtStrings list together with an anonymous Comparator object.

In the compare() method implementation, we first parse the two date-time strings into Date objects and then compare two Date objects.

If our Java version is 8 or higher, we can use the powerful comparison with lambdas feature to make our code compact and easier to read:

final DateTimeFormatter dfm = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm");
dtStrings.sort(Comparator.comparing(s -> LocalDateTime.parse(s, dfm)));
assertEquals(EXPECTED, dtStrings);

It’s important to note that both the Collections.sort() and list.sort() approaches facilitate in-place sorting, meaning that the original list is modified directly without creating a new sorted copy. This offers notable advantages in terms of memory efficiency and performance.

4. Using the Stream API

Additionally, to sort a list of date-time strings, we can take a three-step approach:

  • Convert String elements to LocalDateTime instances
  • Sort those LocalDateTime objects
  • Convert the LocalDateTime objects back to Strings

The Stream API allows us to process collections conveniently. If we implement this idea with the Stream API, the map() method can help us perform the conversions:

DateTimeFormatter dfm = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm");
List<String> sortedList = dtStrings.stream()
  .map(s -> LocalDateTime.parse(s, dfm))
  .sorted()
  .map(dfm::format)
  .collect(Collectors.toList());
assertEquals(EXPECTED, sortedList);

Unlike the Collections.sort() and list.sort() solutions, this approach doesn’t change the original list. Instead, it returns a new list to hold the sorted strings.

5. Using a TreeMap

The TreeMap class in Java provides automatic sorting of entries based on their keys. By using this feature, we can easily sort date-time strings by creating a TreeMap with key-value pairs of type LocalDateTime and String.

Then, if we take all values from the TreeMap, for example, using the treeMap.values() method, we get the sorted result.

Next, let’s implement this in a test:

DateTimeFormatter dfm = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm");
Map<LocalDateTime, String> dateFormatMap = new TreeMap<>();
dtStrings.forEach(s -> dateFormatMap.put(LocalDateTime.parse(s, dfm), s));
List<String> result = new ArrayList<>(dateFormatMap.values());
assertEquals(EXPECTED, result);

This solution is straightforward. However, it has a drawback. As standard Java Map cannot have duplicate keys, duplicate date-time strings will be lost in the sorted list. Therefore, it’s good to ensure the list doesn’t contain duplicate values before we apply the TreeMap approach to sort them.

6. Conclusion

In this article, we’ve explored different general solutions to sort date strings:

  • Collections.sort() and list.sort() with a custom Comparator (in-place sorting)
  • Convert strings to date objects, sort the objects, and convert them back to date strings
  • The TreeMap approach

As usual, all code snippets presented here are available over on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.