Filippo Calabrese
Filippo Calabrese

Reputation: 69

Java - How to filter a List of Date?

I have a list storing Date Objects in this form:

Mon Jan 30 18:00:00 GMT+00:00 2017
Mon Jan 30 21:00:00 GMT+00:00 2017
Tue Jan 31 00:00:00 GMT+00:00 2017
Tue Jan 31 03:00:00 GMT+00:00 2017
Tue Jan 31 06:00:00 GMT+00:00 2017

I need a way to filter my list and keep only the last date for each day.

This is the current status of my code:

for(int i = 0; i< timeDate.size(); i++){

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(timeDate.get(i));

        int day = calendar.get(Calendar.DAY_OF_MONTH);
        int month = calendar.get(Calendar.MONTH);
        int hour = calendar.get(Calendar.HOUR);

        for(int j=i; j<timeDate.size(); j++){
            Date currentDate = timeDate.get(j);
            calendar.setTime(currentDate);

            int dayC = calendar.get(Calendar.DAY_OF_MONTH);
            int monthC = calendar.get(Calendar.MONTH);
            int hourC = calendar.get(Calendar.HOUR);

            if(day==dayC && month==monthC && hourC > hour){
                timeDate.remove(i);
            }
        }
    }

Upvotes: 2

Views: 3924

Answers (2)

Basil Bourque
Basil Bourque

Reputation: 339382

Using java.time

The Calendar and Date classes have supplanted by the java.time classes. Avoid the troublesome legacy classes like the Plague.

Convert each Date you say you are given to an Instant, a moment on the timeline in UTC.

Instant instant = myDate.toInstant();

Collect into a List.

List<> instants = new ArrayList<>();
instants.add( myDate.toInstant() );
…
Collections.reverse( instants );  // if not already in descending sorted order. 

As seen in the Answer by Darshan, make a Map but of LocalDate and ZonedDateTime.

We need to assign a time zone to Instant to get à ZonedDateTime. For any given moment, the date varies around the globe by zone.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone();

Extract a LocalDate.

LocalDate ld = zdt.toLocalDate();

Use that as your key to map. If no such key, add it and add the ZonedDateTime as the value for that Map entry.

If there is a key for that date, retrieve the value, the ZonedDateTime and compare. Compare with isAfter method. Replace the value if one in hand is later.

Tip: if you sort the inputs by latest ones first such as Collections.reverse( instants ), you can optimize. If you find a key for a particular LocalDate, don't bother checking with a call to isAfter. You know any value entered for that key is already the latest. So move on to next input.

You can further optimize by not even checking the Map. Just remember the last LocalDate added to the Map. Compare against the incoming LocalDate with a call to isEqual. If equal, move on to next input.

Upvotes: 1

Darshan Mehta
Darshan Mehta

Reputation: 30839

Here you go:

public static void main(String[] args){
    List<String> list = new ArrayList<>();
    SimpleDateFormat dateFomat = new SimpleDateFormat("E MMM dd hh:mm:ss z yyyy");
    SimpleDateFormat yyyyMMddFormat = new SimpleDateFormat("yyyyMMdd"); 
    list.add("Mon Jan 30 18:00:00 GMT+00:00 2017");
    list.add("Mon Jan 30 21:00:00 GMT+00:00 2017");
    list.add("Tue Jan 31 00:00:00 GMT+00:00 2017");
    list.add("Tue Jan 31 03:00:00 GMT+00:00 2017");
    list.add("Tue Jan 31 06:00:00 GMT+00:00 2017");

    Map<String, List<Date>> dateMap = list.stream()
    .map(s -> {
        try {
            return dateFomat.parse(s);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    })
    .collect(Collectors.groupingBy(s -> yyyyMMddFormat.format(s), Collectors.toList()));

    List<Date> lastDates = new ArrayList<>();
    for(Map.Entry<String, List<Date>> entry : dateMap.entrySet()){
        lastDates.add(Collections.max(entry.getValue()));
    }

    System.out.println(lastDates);
}

Upvotes: 3

Related Questions