186

Every example I find is about doing this alphabetically, while I need my elements sorted by date.

My ArrayList contains objects on which one of the datamembers is a DateTime object. On DateTime I can call the functions:

lt() // less-than
lteq() // less-than-or-equal-to

So to compare I could do something like:

if(myList.get(i).lt(myList.get(j))){
    // ...
}

What should I do inside the if block?

NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
  • 3
    I posted the solution but if you want to get an insight on ordering you should read about ordering algorithms (bubblesort, mergesort, quicksort, etc). – helios May 08 '11 at 11:26
  • Thanks, I'll have a look at those, I don't know anything about sorting –  May 08 '11 at 11:43
  • Several useful Java 1.8 solutions could be found in this thread: https://stackoverflow.com/questions/36361156/null-safe-date-comparator-for-sorting-in-java-8-stream – lradacher Mar 26 '18 at 08:17
  • You can find the answer for both ascending and descending here https://stackoverflow.com/a/66772568/5915318 – David Kariuki Mar 23 '21 at 23:21

14 Answers14

477

You can make your object comparable:

public static class MyObject implements Comparable<MyObject> {

  private Date dateTime;

  public Date getDateTime() {
    return dateTime;
  }

  public void setDateTime(Date datetime) {
    this.dateTime = datetime;
  }

  @Override
  public int compareTo(MyObject o) {
    return getDateTime().compareTo(o.getDateTime());
  }
}

And then you sort it by calling:

Collections.sort(myList);

However sometimes you don't want to change your model, like when you want to sort on several different properties. In that case, you can create comparator on the fly:

Collections.sort(myList, new Comparator<MyObject>() {
  public int compare(MyObject o1, MyObject o2) {
      return o1.getDateTime().compareTo(o2.getDateTime());
  }
});

However, the above works only if you're certain that dateTime is not null at the time of comparison. It's wise to handle null as well to avoid NullPointerExceptions:

public static class MyObject implements Comparable<MyObject> {

  private Date dateTime;

  public Date getDateTime() {
    return dateTime;
  }

  public void setDateTime(Date datetime) {
    this.dateTime = datetime;
  }

  @Override
  public int compareTo(MyObject o) {
    if (getDateTime() == null || o.getDateTime() == null)
      return 0;
    return getDateTime().compareTo(o.getDateTime());
  }
}

Or in the second example:

Collections.sort(myList, new Comparator<MyObject>() {
  public int compare(MyObject o1, MyObject o2) {
      if (o1.getDateTime() == null || o2.getDateTime() == null)
        return 0;
      return o1.getDateTime().compareTo(o2.getDateTime());
  }
});
Domchi
  • 10,705
  • 6
  • 54
  • 64
  • 1
    Good answer. Why do you need to include the versions without null checking? What is the advantage? If the correct way is the second you can only include it and make the important info more attractive. – amotzg Sep 09 '12 at 14:04
  • 18
    Two reasons - simplicity and fail-fast. You want code to be as simple as possible, and if you are certain that your property should not be null you probably want your code to fail as soon as possible if you encounter null, instead passing invalid data on and breaking even further from the place where invalid data was introduced. – Domchi Sep 10 '12 at 15:55
  • 3
    if o1 or o2 is null, return 0; //this line might cause bug as returning 0 implies that they're equal. – tanyehzheng Oct 17 '13 at 03:03
  • @tanyehzheng, that's correct, it is misleading, but note that there is a difference between .compareTo() which is used for sorting and .equals(). It really depends on how you want your nulls to be handled during sort. – Domchi Oct 21 '13 at 07:18
  • 1
    You should check for each date's null separately and sort as desired (either null sorts at the beginning or end of the sequence). That is, if one date is null and one is not null, return a 1 or -1. Without doing that, the nulls are not sorted and remain wherever they happened to be in the list before the sort. – droozen Nov 13 '14 at 15:53
  • You can find the answer for both ascending and descending here https://stackoverflow.com/a/66772568/5915318 – David Kariuki Mar 23 '21 at 23:22
112

Since Java 8 the List interface provides the sort method. Combined with lambda expression the easiest solution would be

// sort DateTime typed list
list.sort((d1,d2) -> d1.compareTo(d2));
// or an object which has an DateTime attribute
list.sort((o1,o2) -> o1.getDateTime().compareTo(o2.getDateTime()));
// or like mentioned by Tunaki
list.sort(Comparator.comparing(o -> o.getDateTime()));

Reverse sorting

Java 8 comes also with some handy methods for reverse sorting.

//requested by lily
list.sort(Comparator.comparing(o -> o.getDateTime()).reversed());
Paul Wasilewski
  • 9,762
  • 5
  • 45
  • 49
  • 11
    Even better would be `list.sort(Comparator.comparing(o -> o.getDateTime()));` – Tunaki May 18 '16 at 07:42
  • 40
    How about this: `list.sort(Comparator.comparing(MyObject::getDateTime)` – whitebrow Apr 10 '18 at 08:56
  • 1
    @Tunaki how to do reverse sorting? – lily Jan 06 '20 at 08:38
  • 1
    @lily, Collections.sort(list, Collections.reverseOrder()); – sanghavi7 Sep 18 '20 at 08:35
  • 5
    Just to make sure everyone is on the same page, examples like this: `list.sort(Comparator.comparing(MyObject::getDateTime));` will return you the earliest date on the first place, and the most recent date on the last. If you want it otherwise, just reverse it as you can see above. – Oliver Apr 12 '21 at 14:42
19

You can use Collections.sort method. It's a static method. You pass it the list and a comparator. It uses a modified mergesort algorithm over the list. That's why you must pass it a comparator to do the pair comparisons.

Collections.sort(myList, new Comparator<MyObject> {
   public int compare(MyObject o1, MyObject o2) {
      DateTime a = o1.getDateTime();
      DateTime b = o2.getDateTime();
      if (a.lt(b)) 
        return -1;
      else if (a.lteq(b)) // it's equals
         return 0;
      else
         return 1;
   }
});

Note that if myList is of a comparable type (one that implements Comparable interface) (like Date, Integer or String) you can omit the comparator and the natural ordering will be used.

helios
  • 13,574
  • 2
  • 45
  • 55
14
list.sort(Comparator.comparing(o -> o.getDateTime()));

The best answer IMHO from Tunaki using Java 8 lambda

Stimpson Cat
  • 1,444
  • 19
  • 44
8

Given MyObject that has a DateTime member with a getDateTime() method, you can sort an ArrayList that contains MyObject elements by the DateTime objects like this:

Collections.sort(myList, new Comparator<MyObject>() {
    public int compare(MyObject o1, MyObject o2) {
        return o1.getDateTime().lt(o2.getDateTime()) ? -1 : 1;
    }
});
WhiteFang34
  • 70,765
  • 18
  • 106
  • 111
6

This is how I solved:

Collections.sort(MyList, (o1, o2) -> o1.getLastModified().compareTo(o2.getLastModified()));

Hope it help you.

Igor Escobar
  • 1,047
  • 1
  • 12
  • 13
6

Here's the answer of how I achieve it:

Mylist.sort(Comparator.comparing(myClass::getStarttime));
SHR
  • 7,940
  • 9
  • 38
  • 57
Zhengyu Chen
  • 61
  • 1
  • 1
4

Future viewers, I think this is the simplest solution, if your model contains a string type date ("2020-01-01 10:00:00" for example), then just write the following line to sort the data by date descending from newest to the oldest:

Collections.sort(messages, (o1, o2) -> o2.getMessageDate().compareTo(o1.getMessageDate()));
2

All the answers here I found to be un-neccesarily complex for a simple problem (at least to an experienced java developer, which I am not). I had a similar problem and chanced upon this (and other) solutions, and though they provided a pointer, for a beginner I found as stated above. My solution, depends on where in the the Object your Date is, in this case, the date is the first element of the Object[] where dataVector is the ArrayList containing your Objects.

Collections.sort(dataVector, new Comparator<Object[]>() {
    public int compare(Object[] o1, Object[] o2) {
        return ((Date)o1[0]).compareTo(((Date)o2[0]));
    }
});
Nepaluz
  • 669
  • 1
  • 12
  • 27
  • 6
    How is your answer less complicated or more correct than other answers here? To my opinion, WhiteFang32's answer for instance is very similar and more concise. – amotzg Sep 09 '12 at 14:22
  • Been away for a while, so did not see the response, but then again, better late than never. I think the conciseness in WhiteFang's answer was its drawback to my (then) inexperienced java developer eyes! The inclusion of the typecasting in my response was the clincher (in my mind then at least). What is left is where you plucked the claim that my answer was more correct than others? Letting off steam I suppose.. all is forgiven! – Nepaluz Jan 07 '13 at 19:56
  • The o.getDateTime() was not about typing, it is about the OP's description of a `DateTime` object that is contained inside another object. If it was only `Date` or `DateTime` objects that are `Comparable` there was no need for a `Comparator` in the first place. – amotzg Jan 08 '13 at 09:47
  • Didn't meant to say your answer is less correct or otherwise less good. I was just me looking for info to help me better understand it. I'm sorry if it seemed to be otherwise. – amotzg Jan 08 '13 at 09:51
2

With introduction of Java 1.8, streams are very useful in solving this kind of problems:

Comparator <DateTime> myComparator = (arg1, arg2) 
                -> {
                    if(arg1.lt(arg2)) 
                       return -1;
                    else if (arg1.lteq(arg2))
                       return 0;
                    else
                       return 1;
                   };

ArrayList<DateTime> sortedList = myList
                   .stream()
                   .sorted(myComparator)
                   .collect(Collectors.toCollection(ArrayList::new));
Tinki
  • 1,486
  • 1
  • 21
  • 32
1

This may be an old response but I used some examples from this post to create a comparator that would sort an ArrayList of HashMap<String, String> by one object in the list, that being the timestamp.

I have these objects:

ArrayList<Map<String, String>> alList = new ArrayList<Map<String, String>>();

The map objects are as follows:

Map<String, Object> map = new HashMap<>();
        // of course this is the actual formatted date below in the timestamp
        map.put("timestamp", "MM/dd/yyyy HH:mm:ss"); 
        map.put("item1", "my text goes here");
        map.put("item2", "my text goes here");

That mapping is what I use to load all my objects into the array list, using the alList.add(map) function, within a loop.

Now, I created my own comparator:

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

 public class DateSorter implements Comparator {
     public int compare(Object firstObjToCompare, Object secondObjToCompare) {
    String firstDateString = ((HashMap<String, String>) firstObjToCompare).get("timestamp");
    String secondDateString = ((HashMap<String, String>) secondObjToCompare).get("timestamp");

    if (secondDateString == null || firstDateString == null) {
        return 0;
    }

    // Convert to Dates
    DateTimeFormatter dtf = DateTimeFormat.forPattern("MM/dd/yyyy HH:mm:ss");
    DateTime firstDate = dtf.parseDateTime(firstDateString);
    DateTime secondDate = dtf.parseDateTime(secondDateString);

    if (firstDate.isAfter(secondDate)) return -1;
    else if (firstDate.isBefore(secondDate)) return 1;
    else return 0;
    }
}

I can now just call the Comparator at any time on the array and it will sort my array, giving me the Latest timestamp in position 0 (top of the list) and the earliest timestamp at the end of the list. New posts get put to the top basically.

Collections.sort(alList, new DateSorter());

This may help someone out, which is why I posted it. Take into consideration the return statements within the compare() function. There are 3 types of results. Returning 0 if they are equal, returning >0 if the first date is before the second date and returning <0 if the first date is after the second date. If you want your list to be reversed, then just switch those two return statements! Simple =]

Brandon
  • 1,401
  • 1
  • 16
  • 25
  • I wanted to add a comment on this. Of course there are "NullPointerExceptions" when handling the array list (given the return 0 statement). So you'll have to handle them as each case will be different. For example a list with 0 objects will generate a NullPointerException, or a list with 1 object! – Brandon Nov 03 '15 at 17:40
1

Use the below approach to identify dates are sort or not

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

boolean  decendingOrder = true;
    for(int index=0;index<date.size() - 1; index++) {
        if(simpleDateFormat.parse(date.get(index)).getTime() < simpleDateFormat.parse(date.get(index+1)).getTime()) {
            decendingOrder = false;
            break;
        }
    }
    if(decendingOrder) {
        System.out.println("Date are in Decending Order");
    }else {
        System.out.println("Date not in Decending Order");
    }       
}   
Vikas Rathour
  • 231
  • 3
  • 9
  • 1
    It doesn’t seem to answer the question. And please don’t teach the young ones to use the long outdated and notoriously troublesome `SimpleDateFormat` class. At least not as the first option. And not without any reservation. Today we have so much better in [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/) and its `DateTimeFormatter`. – Ole V.V. Mar 07 '19 at 10:41
0

Pass the ArrayList In argument.

    private static void order(ArrayList<Object> list) {

    Collections.sort(list, new Comparator() {

        public int compare(Object o2, Object o1) {

            String x1 =  o1.Date;
            String x2 =  o2.Date;

                return  x1.compareTo(x2);

        }
    });
}
Senghani Maulik
  • 119
  • 2
  • 7
0

The Date class already implements Comparator interface. Assuming you have the class below:

public class A {

    private Date dateTime;

    public Date getDateTime() {
        return dateTime;
    }

    .... other variables

}

And let's say you have a list of A objects as List<A> aList, you can easily sort it with Java 8's stream API (snippet below):

import java.util.Comparator;
import java.util.stream.Collectors;

...

aList = aList.stream()
        .sorted(Comparator.comparing(A::getDateTime))
        .collect(Collectors.toList())
Anthony Anyanwu
  • 987
  • 11
  • 7