如何使用Java Streams API正确过滤开始日期和结束日期之间的日期?

时间:2019-03-29 23:36:44

标签: java spring-boot java-stream jhipster localdate

因此,我一直在使用Java Streams API,并且尝试过滤数据库中的日期,其中某些内容的开始日期在当前日期之前,而结束日期在当前日期之后。我已经尝试了多种方法,但到目前为止我尝试过的所有方法似乎都没有效果。

这是我到目前为止尝试过的:

  

我尝试实现ChronoLocalDate接口,并使用了.isBefore() and。isAfter()`,但是日期没有正确过滤

     

目前,我尝试使用LocalDate,并尝试使用LocalDate.now()yyyy-MM-dd转换为LocalDate rightNow = LocalDate.now(); String formatString = rightNow.format(DateTimeFormatter.ISO_LOCAL_DATE); 格式(这是数据库中的日期格式)。以下代码:

The method format(DateTimeFormatter) is undefined for the type LocalDate

但是,这不起作用,并导致以下错误:

LocalDate.format()

我从2018年的各种示例中获得了上面的代码。 var sqlite3 = require('sqlite3').verbose(); var db = new sqlite3.Database('./books.db'); function authenticate(){ db.get("SELECT Username FROM Authentication"), function(err,row) { console.log('test') } } 已经折旧了吗?

此外,我还没有找到任何有关使用LocalDate在开始日期和结束日期之间进行过滤的示例。

从这里获得的任何帮助将不胜感激。提前致谢。

4 个答案:

答案 0 :(得分:0)

好吧,您可以使用Java8 streamsLocalDate做类似的事情。

    public static void main(String[] args) {
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String startTextDateFromDB = "2019-03-14";
        String endTextDateFromDB = "2019-05-14";
        LocalDate startDate = LocalDate.parse(startTextDateFromDB, dateFormatter);
        LocalDate endDate = LocalDate.parse(endTextDateFromDB, dateFormatter);
        List<LocalDate> getList = getDatesInBetween(startDate, endDate);
        System.out.println(Arrays.asList(getList));

    }

    //return a list of all localdates between two dates
    public static List<LocalDate> getDatesInBetween(
            LocalDate startDate, LocalDate endDate) {
        //get numbers between two dates
        long numbersBetween = ChronoUnit.DAYS.between(startDate, endDate);
        //collect each localdate from start date until end date 
        return IntStream.iterate(0, i -> i + 1)
                .limit(numbersBetween)
                .mapToObj(i -> startDate.plusDays(i))
                .collect(Collectors.toList());        
    }
}

答案 1 :(得分:0)

下面是一个如何应用过滤器的示例。我假设您有一个包含Foo元素的列表,并且该类有两个字段:startDateendDate

LocalDate now = LocalDate.now();
List<LocalDate> dates = dbEntries.stream()
    .filter(t -> t.getStartDate().compareTo(now) < 0 && t.getEndDate().compareTo(now) > 0)
    .collect(Collectors.toList());

Spring Boot可能能够自动将数据库中的日期转换为适当的Temporal实例。也许使用注释。

答案 2 :(得分:0)

SQL中的过滤器

  

因此,我一直在使用Java Streams API,并且试图过滤数据库中的日期,

这是一个矛盾。如果您要在数据库中过滤日期作为查询的一部分(通常是最好的方法),那么就不需要Java流。

SQL中的半开查询

编写查询。我假设我们要查询一对类似于SQL标准DATE类型的数据类型的列,以获取没有日期和时区的仅日期值。

在此查询代码中,我们使用半开方法,其中开头为包含,而结尾为排除。通常,这是处理时间跨度的最佳方法。

String sql = "SELECT * FROM event_ WHERE start_ <= ? AND stop_ > ? ;" ;

今天

我们需要今天的日期才能传递到该?占位符。

时区对于确定日期至关重要。在任何给定时刻,日期都会在全球范围内变化。例如,Paris France午夜之后的几分钟是新的一天,而Montréal Québec仍然是“昨天”。

如果未指定时区,则JVM隐式应用其当前的默认时区。该默认值可能在运行时(!)期间change at any moment,因此您的结果可能会有所不同。最好将您的期望/期望时区明确指定为参数。如果紧急,请与您的用户确认区域。

Continent/Region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用2-4个字母的缩写,例如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;

如果要使用JVM的当前默认时区,请提出要求并作为参数传递。如果省略,代码将变得难以理解,因为我们不确定您是否打算使用默认值,还是像许多程序员一样不知道该问题。

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.
LocalDate today = LocalDate.now( z ) ;

占位符的传递值

我们有今天的日期,因此将其传递给您准备好的对帐单。

myPreparedStatement.setObject( 1 , today ) ;
myPreparedStatement.setObject( 2 , today ) ;

Java中的过滤器

通常最好在SQL中执行尽可能多的过滤,以在数据库的服务器端执行。强大的企业级数据库引擎(例如Postgres)已针对此类工作进行了高度优化。

但是,也许您有某些理由要使用Java而不是数据库来实现这一点。

您必须使用Java pulling from a result set in JDBC逐行检索。因此,您最好进行过滤。这意味着不需要Java流。只需比较LocalDate的值作为起始值和终止值即可。

  

我尝试实现ChronoLocalDate接口,并使用.isBefore()和.isAfter()`,但是日期无法正确过滤

您似乎对 java.time 在这方面的工作感到困惑。 ChronoLocalDate接口不是所要实现的。该接口已在LocalDate日历系统的ISO 8601类中实现在世界其他大部分地区的西部普遍使用。该接口是为实现各种日历系统的作者而存在的,而不是为您和我提供的。至少已经有十二种已经为Java实现的日历系统,包括与Java捆绑在一起的某些系统,例如伊斯兰,日语和泰国日历。 >

顺便说一句, java.time JavaDoc解释说,您通常应该避免使用更通用的接口。如上所述,它们的存在主要是为了实现日历系统的利益。在日常业务编程中,通常应使用更具体的类。例如,使用LocalDate而不是ChronoLocalDate

要比较LocalDate个对象,请调用LocalDate::isBeforeisAfterisEqualequalscompareTo方法

List< Event > events = new ArrayList<>() ;
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
    …
    LocalDate start = rs.getObject( "start_" , LocalDate.class ) ;
    LocalDate stop = rs.getObject( "stop_" , LocalDate.class ) ;
    if( ( ! start.isAfter( today ) ) && ( stop.isBefore( today ) ) { 
        Event event = … ;
        events.add( event ) ;
    } else { 
        // Skip this row. Does not meet our criterion of containing today's date.
    }
}

LocalDateRange

ThreeTen-Extra库使这种工作变得更加容易。该项目为 java.time 类添加了功能。

对于您的特定情况,您可能会发现LocalDateRange类很有帮助。此类将时间跨度表示为一对LocalDate对象。有用的比较方法包括abutscontainsoverlaps等。尽管您可以选择指定全封闭(开头和结尾均为),但默认情况下,这些选项会根据Half-Open方法工作。

让我们使用此类来修改上面的示例代码中的比较。

List< Event > events = new ArrayList<>() ;
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
    …
    LocalDate start = rs.getObject( "start_" , LocalDate.class ) ;
    LocalDate stop = rs.getObject( "stop_" , LocalDate.class ) ;
    LocalDateRange dateRange = LocalDateRange.of( start , stop ) ;   // Instantiate the date range.
    if( ( dateRange.contains( today ) ) {                            // Call `LocalDateRange::contains` rather than write our own comparison logic.
        Event event = … ;
        events.add( event ) ;
    } else { 
        // Skip this row. Does not meet our criterion of containing today's date.
    }
}

智能对象,而不是哑字符串

  

LocalDate rightNow = LocalDate.now();   String formatString = rightNow.format(DateTimeFormatter.ISO_LOCAL_DATE);

为什么要生成字符串?考虑到您的问题陈述,我认为不需要字符串。使用日期时间值时,请使用日期时间对象。不要将字符串用于日期时间业务逻辑。

教程

提示:在Oracle免费提供的 java.time 上阅读the tutorial

答案 3 :(得分:0)

所以我发现了问题所在。我从LocalDate而不是java.joda导入了错误的java.time

因此,从这里开始,我不再使用ChronoLocalDate,但不再使用LocalDate中的java.time,现在我的过滤效果也很好。我很愚蠢的错误,但我发现了。

感谢所有尝试提供帮助的人。

相关问题