java 按开始和结束时间过滤带有日期的 ArrayList

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26075490/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 09:15:26  来源:igfitidea点击:

Filter an ArrayList with Dates by start and end time

javaandroid

提问by EmilDo

I am implementing a simple ListView where the data source is an ArrayList with that contains Name, Start and End dates. In iOS I would use a simple NSPredicate to filter the array but here in Android and Java I am confused of what I should use. Any suggestions are welcomed.

我正在实现一个简单的 ListView,其中数据源是一个包含名称、开始和结束日期的 ArrayList。在 iOS 中,我会使用一个简单的 NSPredicate 来过滤数组,但在 Android 和 Java 中,我不知道应该使用什么。欢迎提出任何建议。

回答by chocksaway

You can use the Date.before, and Date.after methods. These allow you to filter a list of dates (for ones in a specific range (for example January)):

您可以使用 Date.before 和 Date.after 方法。这些允许您过滤日期列表(对于特定范围内的日期(例如一月)):

a. Use a Java 8 filter, with a start, and end date.

一个。使用带有开始日期和结束日期的 Java 8 过滤器。

b. Use a Java loop / iterator, to check start and end date.

湾 使用 Java 循环/迭代器来检查开始和结束日期。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.stream.Collectors;

public class FilterStartAndEndDate {

    private SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
    private Collection<Date> dateList = null;
    private Date start = null;
    private Date end = null;

    private FilterStartAndEndDate() throws ParseException {
        dateList = new ArrayList<Date>() {{
            add(sdf.parse("01/01/2016"));
            add(sdf.parse("02/01/2016"));
            add(sdf.parse("03/02/2016"));
            add(sdf.parse("04/01/2016"));
            add(sdf.parse("05/01/2016"));
        }};

        start = sdf.parse("31/12/2015");
        end = sdf.parse("01/02/2016");
    }

    /**
     * Filter dates with Lambda
     *
     * @throws ParseException
     */
    private void getDatesBetweenStartAndFinishWithFilter() throws ParseException {
        dateList.stream()
                .filter(dates -> dates.after(start) && dates.before(end))
                .collect(Collectors.toList())
                .forEach(januaryDate->System.out.println(januaryDate));
    }

    /**
     * Filter dates with Iterator
     *
     * @throws ParseException
     */
    private void getDatesBetweenStartAndFinish() throws ParseException {
        Collection<Date> datesInJanuaryList = new ArrayList<>();

        for (Date eachDate : dateList) {
            if (eachDate.after(start) && eachDate.before(end)) {
                datesInJanuaryList.add(eachDate);
            }
        }

        for (Date eachDate : datesInJanuaryList) {
            System.out.println(eachDate);
        }
    }


    public static void main(String[] args) throws Exception {
        FilterStartAndEndDate datesInJanuary = new FilterStartAndEndDate();
        datesInJanuary.getDatesBetweenStartAndFinish();
        datesInJanuary.getDatesBetweenStartAndFinishWithFilter();
    }
}

The example code filter dates in January, using a Lambda filter, and a Java iterator. Both use the Date before and after methods.

示例代码过滤器日期为 1 月,使用 Lambda 过滤器和 Java 迭代器。两者都使用 Date before 和 after 方法。

回答by Basil Bourque

Define a class

定义一个类

contains Name, Start and End dates

包含名称、开始和结束日期

Define a class to hold your event name, start date, and stop date.

定义一个类来保存您的事件名称、开始日期和停止日期。

LocalDate

LocalDate

Use the modern java.timeclasses for date-time values. The LocalDateclass represents a date-only value without time-of-day and without time zone. Never use Date, Calendar, SimpleDateFormat, or other terrible old legacy date-time classes.

将现代java.time类用于日期时间值。该LocalDate级表示没有时间一天和不同时区的日期,唯一的价值。永远不要使用DateCalendarSimpleDateFormat或其他糟糕的旧式日期时间类。

class Event {
    String name;
    LocalDate start, stop;

    // Constructor
    public Event ( String name , LocalDate start , LocalDate stop ) {
        this.name = name;
        this.start = start;
        this.stop = stop;
    }

}

Add a method that compares a passed LocalDateto the start and stop dates, returning true if contained within our date range. Usually best to compare using the Half-Open approach where the beginning is inclusivewhile the ending is exclusive.

添加一个方法,将传递LocalDate的a与开始日期和停止日期进行比较,如果包含在我们的日期范围内,则返回 true。通常最好使用半开方法进行比较,其中开头包含而结尾不包含

    public boolean contains ( LocalDate localDate ) {
        // Regarding the beginning date, a short way of saying2 "is equal to or is later than" is "is not before".
        boolean x = ( ! localDate.isBefore( this.start ) ) && localDate.isBefore( this.stop );
        return x;
    }

Build a list of these events.

建立这些事件的列表。

List< Event > events = new ArrayList<>();
events.add( new Event( "alpha" , LocalDate.of( 2018 , Month.JANUARY , 23 ) , LocalDate.of( 2018 , Month.JANUARY , 28 ) ) );
events.add( new Event( "beta" , LocalDate.of( 2018 , Month.FEBRUARY , 23 ) , LocalDate.of( 2018 , Month.FEBRUARY , 28 ) ) );
events.add( new Event( "gamma" , LocalDate.of( 2018 , Month.MARCH , 23 ) , LocalDate.of( 2018 , Month.MARCH , 28 ) ) );

Loop these events, checking each if it contains our target date.

循环这些事件,检查每个事件是否包含我们的目标日期。

LocalDate target = LocalDate.of( 2018 , Month.FEBRUARY , 25 );
List< Event > hits = new ArrayList<>( events.size() );
for ( Event event : events ) {
    if ( event.contains( target ) ) {
        hits.add( event );
    }
}

Alternatively, use Java Streams with lambda syntax, instead of that for-each loop. Same effect; use whichever syntax approach appeals to you.

或者,使用带有 lambda 语法的 Java Streams,而不是 for-each 循环。效果一样;使用您喜欢的任何语法方法。

LocalDate target = LocalDate.of( 2018 , Month.FEBRUARY , 25 );
List< Event > hits = 
    events
    .stream()
    .filter( event -> event.contains( target ) )
    .collect( Collectors.toList() )
;

Put all this together into one big class, for the sake of demonstration. I would not nest this Eventclass in real work.

为了演示,将所有这些放在一个大类中。我不会Event在实际工作中嵌套这个类。

package com.basilbourque.example;

import java.time.LocalDate;
import java.time.Month;
import java.util.ArrayList;
import java.util.List;

public class ListFilterExample {

    public static void main ( String[] args ) {
        ListFilterExample app = new ListFilterExample();
        app.doIt();
    }

    private void doIt () {
        List< Event > events = new ArrayList<>();
        events.add( new Event( "alpha" , LocalDate.of( 2018 , Month.JANUARY , 23 ) , LocalDate.of( 2018 , Month.JANUARY , 28 ) ) );
        events.add( new Event( "beta" , LocalDate.of( 2018 , Month.FEBRUARY , 23 ) , LocalDate.of( 2018 , Month.FEBRUARY , 28 ) ) );
        events.add( new Event( "gamma" , LocalDate.of( 2018 , Month.MARCH , 23 ) , LocalDate.of( 2018 , Month.MARCH , 28 ) ) );

        LocalDate target = LocalDate.of( 2018 , Month.FEBRUARY , 25 );
        List< Event > hits = new ArrayList<>( events.size() );
        for ( Event event : events ) {
            if ( event.contains( target ) ) {
                hits.add( event );
            }
        }
        System.out.println( hits );
    }

    class Event {
        String name;
        LocalDate start, stop;

        public boolean contains ( LocalDate localDate ) {
            // Regarding the beginning date, a short way of saying2 "is equal to or is later than" is "is not before".
            boolean x = ( ! localDate.isBefore( this.start ) ) && localDate.isBefore( this.stop );
            return x;
        }

        // Constructor
        public Event ( String name , LocalDate start , LocalDate stop ) {
            this.name = name;
            this.start = start;
            this.stop = stop;
        }

        @Override
        public String toString () {
            return "Event{ " +
                   "name='" + name + '\'' +
                   "| start=" + start +
                   "| stop=" + stop +
                   " }";
        }
    }
}

When run.

跑的时候。

[Event{ name='beta'| start=2018-02-23| stop=2018-02-28 }]

[事件{名称='测试版'| 开始=2018-02-23| 停止=2018-02-28 }]

LocalDateRange

LocalDateRange

If you want to get fancy, add the ThreeTen-Extralibrary (discussed below) to your project. Use its LocalDateRangeclass to represent your stop-start pair of dates explicitly as a date-range. That class already includes a containsmethod, so no need to write you own.

如果您想变得更有趣,请将ThreeTen-Extra库(如下所述)添加到您的项目中。使用它的LocalDateRange类将您的停止-开始日期明确表示为日期范围。该类已经包含一个contains方法,因此无需编写您自己的方法。

package com.basilbourque.example;

import org.threeten.extra.LocalDateRange;

import java.time.LocalDate;
import java.time.Month;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class ListFilterExample {

    public static void main ( String[] args ) {
        ListFilterExample app = new ListFilterExample();
        app.doIt();
    }

    private void doIt () {
        List< Event > events = new ArrayList<>();
        events.add( new Event( "alpha" , LocalDate.of( 2018 , Month.JANUARY , 23 ) , LocalDate.of( 2018 , Month.JANUARY , 28 ) ) );
        events.add( new Event( "beta" , LocalDate.of( 2018 , Month.FEBRUARY , 23 ) , LocalDate.of( 2018 , Month.FEBRUARY , 28 ) ) );
        events.add( new Event( "gamma" , LocalDate.of( 2018 , Month.MARCH , 23 ) , LocalDate.of( 2018 , Month.MARCH , 28 ) ) );

        LocalDate target = LocalDate.of( 2018 , Month.FEBRUARY , 25 );
        // Lambda syntax, instead of for-each loop.
        List< Event > hits = events.stream().filter( event -> event.contains( target ) ).collect( Collectors.toList() );
        System.out.println( hits );
    }

    class Event {
        String name;
        LocalDateRange dateRange;

        public boolean contains ( LocalDate localDate ) {
            // Regarding the beginning date, a short way of saying2 "is equal to or is later than" is "is not before".
            boolean x = this.dateRange.contains( localDate );
            return x;
        }

        // Constructor
        public Event ( String name , LocalDate start , LocalDate stop ) {
            this.name = name;
            this.dateRange = LocalDateRange.of( start , stop );
        }

        @Override
        public String toString () {
            return "Event{ " +
                   "name='" + name + '\'' +
                   "| dateRange=" + dateRange +
                   " }";
        }
    }
}

[Event{ name='beta'| dateRange=2018-02-23/2018-02-28 }]

[事件{名称='测试版'| 日期范围=2018-02-23/2018-02-28 }]



About java.time

关于java.time

The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.

现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310

You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*classes.

您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*

Where to obtain the java.time classes?

从哪里获得 java.time 类?

The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多