arsenallavigne
arsenallavigne

Reputation: 141

Android - How to sort arrayList by date?

I'm trying to sort my arrayList by date. I stored the date on Firebase each time I receive a notification and is retrieved from there. I'm using Collections.sort but I don't know how to implement onto my codes as my date format starts with a number in a string format like "12 Jul 2017 at 12:00am".

I've seen some examples of this on stackoverflow but I don't know how to make it work in my case. I will post screenshots and my codes below.

The dates are not sorted.

enter image description here

NotificationFragment.java

public class NotificationFragment extends Fragment {
        prepareNotification1();
        sortDate();
        return v;
    }

       private void prepareNotification1() {
            FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
            String userID = user.getUid();

  mRef.child("customers").child(userID).child("Notification").addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                    Notification menu = dataSnapshot.getValue(Notification.class);
                    notificationList.add(menu);
                mAdapter.notifyDataSetChanged();
            }
 });
    }

    public void sortDate() {
        Collections.sort(notificationList, new Comparator<Notification>() {
            @Override
            public int compare(Notification lhs, Notification rhs) {
                return lhs.getDate().compareTo(rhs.getDate());
            }
        });
        mAdapter = new NotificationAdapter(getContext(), notificationList);
        mRecyclerView.setAdapter(mAdapter);
    }
}

MyFirebaseMessagingService.java

public class MyFirebaseMessagingService extends FirebaseMessagingService {
@Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Calendar cal = Calendar.getInstance();

        String currentDateTimeString = DateFormat.getDateInstance().format(new Date());

        SimpleDateFormat df = new SimpleDateFormat("hh:mm a");
        String currentTime = df.format(cal.getTime());

        String notificationTime = currentDateTimeString + " at " + currentTime;

        Notification newNotification = new Notification(remoteMessage.getData().get("body"), notificationTime);
        mRef.child("customers").child(userID).child("Notification").push().setValue(newNotification);
}

Notification.java

public class Notification {
    private String message;
    private String date;


    public Notification(){
    }

    public Notification(String message, String date){
        this.message = message;
        this.date = date;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

Upvotes: 5

Views: 21270

Answers (6)

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79085

You can simply parse the date-time strings into LocalDateTime and perform a natural sorting.

Using Stream:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("d MMM u 'at' h:m a", Locale.UK);
        
        Stream.of(
                    "10 Jul 2017 at 10:59 pm",
                    "10 Jul 2017 at 10:59 pm",
                    "11 Jul 2017 at 11:15 pm",
                    "9 Jul 2017 at 11:15 pm"
                )
                .map(s -> LocalDateTime.parse(s, dtf))
                .sorted()
                .forEach(dt -> System.out.println(dtf.format(dt)));
    }
}

Output:

9 Jul 2017 at 11:15 pm
10 Jul 2017 at 10:59 pm
10 Jul 2017 at 10:59 pm
11 Jul 2017 at 11:15 pm

Non-Stream solution:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("d MMM u 'at' h:m a", Locale.UK);
        List<LocalDateTime> listLdt = new ArrayList<>();
        
        List<String> listDtStr = 
                Arrays.asList(
                                "10 Jul 2017 at 10:59 pm",
                                "10 Jul 2017 at 10:59 pm",
                                "11 Jul 2017 at 11:15 pm",
                                "9 Jul 2017 at 11:15 pm"
                            );
        
        // Add the strings, parsed into LocalDateTime, to listLdt
        for(String s: listDtStr) {
            listLdt.add(LocalDateTime.parse(s, dtf));
        }
        
        // Sort listLdt
        Collections.sort(listLdt);
        
        // Display
        for(LocalDateTime ldt: listLdt) {
            System.out.println(ldt.format(dtf));
        }
    }
}

Output:

9 Jul 2017 at 11:15 pm
10 Jul 2017 at 10:59 pm
10 Jul 2017 at 10:59 pm
11 Jul 2017 at 11:15 pm

Learn more about the modern date-time API from Trail: Date Time.

Using legacy date-time API:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;

public class Main {
    public static void main(String[] args) throws ParseException {
        final SimpleDateFormat sdf = new SimpleDateFormat("d MMM u 'at' h:m a", Locale.UK);
        List<Date> listDate = new ArrayList<>();
        
        List<String> listDtStr = 
                Arrays.asList(
                                "10 Jul 2017 at 10:59 pm",
                                "10 Jul 2017 at 10:59 pm",
                                "11 Jul 2017 at 11:15 pm",
                                "9 Jul 2017 at 11:15 pm"
                            );
        
        // Add the strings, parsed into LocalDateTime, to listDate
        for(String s: listDtStr) {
            listDate.add(sdf.parse(s));
        }
        
        // Sort listDate
        Collections.sort(listDate);
        
        // Display
        for(Date date: listDate) {
            System.out.println(sdf.format(date));
        }
    }
}

Output:

9 Jul 4 at 11:15 pm
10 Jul 5 at 10:59 pm
10 Jul 5 at 10:59 pm
11 Jul 6 at 11:15 pm

Note: The java.util date-time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API* .


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Upvotes: 2

David Kariuki
David Kariuki

Reputation: 1756

Sort ArrayList by Date in Ascending and Descending order

In my answer I will use an ArrayList for debts named debtsArrayList. This answer will show how to sort an ArrayList with objects by date in both ascending and descending order.

Sort comparator class

First create a SortComparator class to hold the functions to sort by date in ascending and descending order.

public class SortComparator {

    /**
     * Class to sort list by Date
     */
    public static class SortBy_Date {

        /**
         * Class to sort list by Date in ascending order
         */
        public static class Ascending implements Comparator<JB_Debts> {

            @Override
            public int compare(JB_Debts jbDebts1, JB_Debts jbDebts2) {

                // Create DateFormat
                DateFormat dateFormat = DateFormat.getDateInstance(
                        DateFormat.FULL, Locale.ENGLISH);

                // Catch Parse errors
                try {

                    // Parse dates
                    Date date1 = dateFormat.parse(jbDebts1.getDate());
                    Date date2 = dateFormat.parse(jbDebts2.getDate());

                    // Check if dates are null
                    if ((date1 != null) && (date2 != null)) {

                        // Ascending
                        return (date1.getTime() > date2.getTime() ? 1 : -1);

                    } else {

                        return 0; // Return 0 to leave it at current index
                    }
                } catch (Exception exception) {

                    exception.printStackTrace();
                }

                return 0;
            }
        }

        /**
         * Class to sort list by Date in descending order
         */
        public static class Descending implements Comparator<JB_Debts> {

            @Override
            public int compare(JB_Debts jbDebts1, JB_Debts jbDebts2) {

                // Create DateFormat
                DateFormat dateFormat = DateFormat.getDateInstance(
                        DateFormat.FULL, Locale.ENGLISH);

                // Catch Parse and NullPointerExceptions
                try {

                    // Parse dates
                    Date date1 = dateFormat.parse(jbDebts1.getDate());
                    Date date2 = dateFormat.parse(jbDebts2.getDate());

                    // Check if dates are null
                    if ((date1 != null) && (date2 != null)) {

                        // Descending
                        return (date1.getTime() > date2.getTime() ? -1 : 1);

                    } else {

                        return 0; // Return 0 to leave it at current index
                    }
                } catch (Exception exception) {

                    exception.printStackTrace();
                }

                return 0;
            }
        }
    }
}

In my example I am using an ArrayList with objects ArrayList<JB_Debts> where JB_Debts is my Java bean class with getter and setter methods.

    public class JB_Debts {

    private String date; // Our date string

    /**
     * Default constructor
     */
    public JB_Debts2() {
    }

    /**
     * Function to get date
     */
    public String getDate() {

        return date;
    }

    /**
     * Function to set date
     *
     * @param date - Date
     */
    public void setDate(String date) {

        this.date = date;
    }
}

Using the class with collections

We will then use this class with Java collections to sort our ArrayList<JB_Debts> with objects based on Date in ascending and descending order.

// Create ArrayList
ArrayList<JB_Debts> debtsArrayList = new ArrayList();

Collections.sort(debtsArrayList,
            new SortComparator.SortBy_Date.Ascending());

Collections.sort(debtsArrayList,
            new SortComparator.SortBy_Date.Descending());

Note

Please note that I stored the date in my ArrayList as a string. To sort them, I parsed the string to date as below:

// Create DateFormat with Locale
DateFormat dateFormat = DateFormat.getDateInstance(
                DateFormat.FULL, Locale.ENGLISH);

// Create DateFormat without Locale
DateFormat dateFormat = DateFormat.getDateInstance(
                DateFormat.FULL);

You can replace the DateFormat.FULL with a date format of your choice e.g. "dd/MM/yyyy hh:mm a" which will then look as below:

// Create DateFormat with Locale
DateFormat dateFormat = new SimpleDateFormat(
            "dd/MM/yyyy hh:mm a", Locale.ENGLISH);

// Create DateFormat without Locale
DateFormat dateFormat = new SimpleDateFormat(
            "dd/MM/yyyy hh:mm a");

I hope this helps

Upvotes: 2

Usman Rana
Usman Rana

Reputation: 2142

Instead of setting date like following in Notification model.

String notificationTime = currentDateTimeString + " at " + currentTime;

you can save time as System.currentTimeinMillis(); and while displaying then parse it to Date as following

DateFormat f = new SimpleDateFormat("dd/MM/yyyy hh:mm a");
f.parse(timeStamp);

Upvotes: 0

Artem Samokhin
Artem Samokhin

Reputation: 163

As I understand, Notification.getDate() returns String value. So, use

public static Date toDate(String value) throws ParseException {
    DateFormat format = new SimpleDateFormat("d MMMM yyyy 'at' HH:mm'am'", Locale.ENGLISH);
    return format.parse(value);
}

this method to det Date from your String. Just get two dates and use Date.compareTo method.

date1 = toDate(lhs.getDate());
date2 = toDate(rhs.getDate());
date1.compareTo(date2);

Upvotes: 1

SpaceBison
SpaceBison

Reputation: 3151

Consider storing the date in Notification as a long (unix time) or a Date (LocalDateTime if you're using Java 8 support) and formatting it as a String only when displaying it to the UI.

Upvotes: 5

Ritt
Ritt

Reputation: 3349

Do sorting after parsing the date.

Collections.sort(notificationList, new Comparator<Notification>() {
            DateFormat f = new SimpleDateFormat("dd/MM/yyyy '@'hh:mm a");
            @Override
            public int compare(Notification lhs, Notification rhs) {
                try {
                    return f.parse(lhs.getDate()).compareTo(f.parse(rhs.getDate()));
                } catch (ParseException e) {
                    throw new IllegalArgumentException(e);
                }
            }
        })

If your date is in some other format, write the DateFormat accordingly.

Upvotes: 11

Related Questions