5

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;
    }
}
8
  • Welcome to Stack Overflow! Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a Minimal, Complete, and Verifiable example. Commented Jul 12, 2017 at 5:51
  • Is getDate() returning String or Date foramt? Commented Jul 12, 2017 at 5:55
  • @UsmanRana String format. I stored it as a string in Firebase each time I receive a notification. Commented Jul 12, 2017 at 5:55
  • 1
    I don't know Firebase, but assuming it is even remotely similar to other databases it must have a date type. Store your dates in this type. Commented Jul 12, 2017 at 5:57
  • please print the value of getDate in Logs and post here, there might be some issue in format Commented Jul 12, 2017 at 5:58

6 Answers 6

11

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Don't know why this answer have any upvotes. Its working fine for me. Thanks Ritesh.
5

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.

1 Comment

Oh thanks, I think I get it. I store it as a string in my 'Notification'
2

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

Comments

2

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.

Comments

1

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

Comments

0

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

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.