190

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?

5
  • 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). Commented May 8, 2011 at 11:26
  • Thanks, I'll have a look at those, I don't know anything about sorting Commented May 8, 2011 at 11:43
  • Several useful Java 1.8 solutions could be found in this thread: stackoverflow.com/questions/36361156/… Commented Mar 26, 2018 at 8:17
  • You can find the answer for both ascending and descending here stackoverflow.com/a/66772568/5915318 Commented Mar 23, 2021 at 23:21
  • 1
    While before Java 8 you may have had a good reason to use a home-grown or third-party DateTime class, this is no longer so. Migrate your code to java.time, the modern Java date and time API. The date-time classes from there implement Comparable, making your sorting task trivial. See the good and thorough answer by Basil Bourque. Commented Oct 4 at 15:45

15 Answers 15

481

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());
  }
});
Sign up to request clarification or add additional context in comments.

6 Comments

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.
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.
if o1 or o2 is null, return 0; //this line might cause bug as returning 0 implies that they're equal.
@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.
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.
|
118

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());

6 Comments

Even better would be list.sort(Comparator.comparing(o -> o.getDateTime()));
How about this: list.sort(Comparator.comparing(MyObject::getDateTime)
@Tunaki how to do reverse sorting?
@lily, Collections.sort(list, Collections.reverseOrder());
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.
|
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.

3 Comments

And does this return myList when it's done or something like that?
It modifiies myList. So its sorted when it finishes
14
list.sort(Comparator.comparing(o -> o.getDateTime()));

The best answer IMHO from Tunaki using Java 8 lambda

Comments

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;
    }
});

1 Comment

What if I want to order basis on the current system time.
7

Here's the answer of how I achieve it:

Mylist.sort(Comparator.comparing(myClass::getStarttime));

2 Comments

this worked like magic for me
the type returned by myClass::getStarttime must implements Comparable for this to work - the question mentions DateTime and two methods, but neither Comparable nor a compareTo() method (( not regarding this question was from 2011 ))
6

This is how I solved:

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

Hope it help you.

1 Comment

how to reverse it by date ?
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()));

Comments

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]));
    }
});

4 Comments

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.
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!
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.
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.
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));

Comments

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 =]

1 Comment

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!
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");
    }       
}   

1 Comment

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 and its DateTimeFormatter.
1

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())

Comments

1

tl;dr

Sort the List by specifying a Comparator.

record Employee ( String name , LocalDate hired ) {}
List < Employee > employees = new ArrayList<>() ;
…
employees.sort
(
            Comparator
                    .comparing( Employee :: hired )
                    .thenComparing( Employee :: name );
);

Or, build the Comparator into the class, implementing Comparable, then tell the List to sort by natural order.

public record Employee( String name , LocalDate hired )
        implements Comparable < Employee >
{
    private static final Comparator < Employee > COMPARATOR =
            Comparator
                    .comparing( Employee :: hired )
                    .thenComparing( Employee :: name );

    @Override
    public int compareTo ( final Employee other )
    {
        return Employee.COMPARATOR.compare( this , other );
    }
}
List < Employee > employees = new ArrayList<>() ;
……
employees.sort() ;

Or, replace that List with a SequencedSet like TreeSet that auto-sorts as you add.

SequencedSet < Employee > seniority = new TreeSet<>() ;

java.time

You said:

one of the datamembers is a DateTime object

Java has no DateTime class. For date-time types, use the java.time classes built into Java 8+.

For a date-only value (year-month-day), use java.time.LocalDate class.

Records

If the main purpose of your class is to transparently communicate shallowly-immutable data, define it as a record.

record Employee ( String name , LocalDate hired ) {}

Sequenced Collections

Java 21 brought sequenced collections. See JEP 431 and video.

class diagram of sequenced collections

SequencedCollection is a super-interface of List and therefore ArrayList.

List#sort

Now you could just call List#sort. Pass a Comparator object to specify how to sort.

List < Employee > employees =
        new ArrayList <>(
                List.of(
                        new Employee( "Alice" , LocalDate.of( 2022 , Month.JANUARY , 23 ) ) ,
                        new Employee( "Bob" , LocalDate.of( 2019 , Month.JANUARY , 23 ) ) ,
                        new Employee( "Carol" , LocalDate.of( 2018 , Month.JANUARY , 23 ) ) ,
                        new Employee( "Davis" , LocalDate.of( 2025 , Month.JANUARY , 23 ) )
                )
        );

employees.sort
(
            Comparator
                    .comparing( Employee :: hired )
                    .thenComparing( Employee :: name );
);

Natural order

We can make that comparator a built-in part of our class. Then objects of our class would know how to sort themselves by implementing the Comparable interface.

public record Employee( String name , LocalDate hired )
        implements Comparable < Employee >
{
    private static final Comparator < Employee > COMPARATOR =
            Comparator
                    .comparing( Employee :: hired )
                    .thenComparing( Employee :: name );

    @Override
    public int compareTo ( final Employee other )
    {
        return Employee.COMPARATOR.compare( this , other );
    }
}

Being able to sort themselves is called “natural order”.

SequencedSet

But instead of sorting your list, I would suggest using a collection that automatically sorts your objects as you add them.

For that collection, I suggest a SequencedCollection that is a SequencedSet, such as TreeSet.

Pass your existing list to the constructor of a TreeSet, a SequencedSet, to automatically sort themselves. Since our Employee objects implement Comparable, we need not specify any Comparator.

SequencedCollection < Employee > seniority = new TreeSet <>( employees );

Dump to console.

seniority.forEach( IO :: println );  // Before Java 25, swap out `IO` for `System.out`. 

When run:

Employee[name=Carol, hired=2018-01-23]
Employee[name=Bob, hired=2019-01-23]
Employee[name=Alice, hired=2022-01-23]
Employee[name=Davis, hired=2025-01-23]

Comments

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);

        }
    });
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.