如何在Java中迭代日期范围?

131 java iteration date

在我的脚本中,我需要在给定开始日期和结束日期的情况下,通过日期范围执行一组操作.
请为我提供使用Java实现此目的的指导.

for ( currentDate = starDate; currentDate < endDate; currentDate++) {

}
Run Code Online (Sandbox Code Playgroud)

我知道上面的代码根本不可能,但我这样做是为了向您展示我想要实现的目标.

Jon*_*eet 180

好吧,你可以使用Java 8的time-API做这样的事情,特别针对这个问题java.time.LocalDate(或者等同于Java 7及更早版本的Joda Time类)

for (LocalDate date = startDate; date.isBefore(endDate); date = date.plusDays(1))
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

完全建议java.time在内置Date/ Calendar类上使用(或Joda Time).

  • @gyabraham:JSR-310正在为Java 8寻找一个非常好的形状. (3认同)
  • 可以确认这个完全相同的代码将使用Java 8的java.time.LocalDate而不是Joda. (3认同)
  • 扩展关于 Joda Time 的观点:尝试自己正确实现这一点比人们想象的要困难,因为围绕夏季时间变化的极端情况。 (2认同)
  • Joda-Time项目现在处于维护模式,并建议迁移到java.time类.正如评论中所提到的,这个Answer的代码在java.time中按原样运行,只需更改`import`语句即可. (2认同)

Bal*_*usC 144

JodaTime很不错,但是,为了完整性和/或如果您更喜欢API提供的设施,这里是标准的API方法.

java.util.Date以下实例开始:

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date startDate = formatter.parse("2010-12-20");
Date endDate = formatter.parse("2010-12-26");
Run Code Online (Sandbox Code Playgroud)

java.util.Calendar如果您还没有使用Java8,这是传统的方法:

Calendar start = Calendar.getInstance();
start.setTime(startDate);
Calendar end = Calendar.getInstance();
end.setTime(endDate);

for (Date date = start.getTime(); start.before(end); start.add(Calendar.DATE, 1), date = start.getTime()) {
    // Do your job here with `date`.
    System.out.println(date);
}
Run Code Online (Sandbox Code Playgroud)

这是Java8的java.time.LocalDate方法,基本上就是JodaTime方法:

LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate end = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

for (LocalDate date = start; date.isBefore(end); date = date.plusDays(1)) {
    // Do your job here with `date`.
    System.out.println(date);
}
Run Code Online (Sandbox Code Playgroud)

如果您想迭代包含结束日期,则分别使用!start.after(end)!date.isAfter(end).


Mar*_*son 67

Java 8样式,使用java.time类:

// Monday, February 29 is a leap day in 2016 (otherwise, February only has 28 days)
LocalDate start = LocalDate.parse("2016-02-28"),
          end   = LocalDate.parse("2016-03-02");

// 4 days between (end is inclusive in this example)
Stream.iterate(start, date -> date.plusDays(1))
        .limit(ChronoUnit.DAYS.between(start, end) + 1)
        .forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

输出:

2016-02-28
2016-02-29
2016-03-01
2016-03-02
Run Code Online (Sandbox Code Playgroud)

替代方案:

LocalDate next = start.minusDays(1);
while ((next = next.plusDays(1)).isBefore(end.plusDays(1))) {
    System.out.println(next);
}
Run Code Online (Sandbox Code Playgroud)

Java 9添加了datesUntil()方法:

start.datesUntil(end.plusDays(1)).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)


Chr*_* M. 26

这与BalusC给出的答案基本相同,但使用while循环代替for循环更具可读性:

Calendar start = Calendar.getInstance();
start.setTime(startDate);

Calendar end = Calendar.getInstance();
end.setTime(endDate);

while( !start.after(end)){
    Date targetDay = start.getTime();
    // Do Work Here

    start.add(Calendar.DATE, 1);
}
Run Code Online (Sandbox Code Playgroud)

  • 如果逻辑涉及"continue"语句,那么这将不起作用,而BalusC的for循环版本使用continue语句. (3认同)

Ole*_*.V. 8

自 Java 9 起,它\xe2\x80\x99s 内置:LocalDate.datesUntil()

\n

到目前为止,答案似乎只考虑了 Java 8 及更早版本。Java 9+的方式是:

\n
    LocalDate startDate = LocalDate.of(2021, Month.JUNE, 29);\n    LocalDate endDate = LocalDate.of(2021, Month.JULY, 3);\n    \n    startDate.datesUntil(endDate).forEach(System.out::println);\n
Run Code Online (Sandbox Code Playgroud)\n

该示例的输出是:

\n
\n
2021-06-29\n2021-06-30\n2021-07-01\n2021-07-02\n
Run Code Online (Sandbox Code Playgroud)\n
\n

虽然开始日期是包含的,但结束日期是排除的,就像我在你的问题中阅读的方式一样。如果有人想要包含结束日期,那么\xe2\x80\x99很简单,只需添加一天即可:

\n
    startDate.datesUntil(endDate.plusDays(1)).forEach(System.out::println);\n
Run Code Online (Sandbox Code Playgroud)\n
\n
2021-06-29\n2021-06-30\n2021-07-01\n2021-07-02\n2021-07-03\n
Run Code Online (Sandbox Code Playgroud)\n
\n

显然,您可以用这种方式迭代几年,就像您可以在我刚刚放置方法引用的地方放置更长的 lambda 一样System.out::println以进行演示的地方放置更长的 lambda 一样。

\n

链接

\n\n


Myk*_*ych 6

Apache Commons

    for (Date dateIter = fromDate; !dateIter.after(toDate); dateIter = DateUtils.addDays(dateIter, 1)) {
        // ...
    }
Run Code Online (Sandbox Code Playgroud)


kus*_*wal 5

private static void iterateBetweenDates(Date startDate, Date endDate) {
    Calendar startCalender = Calendar.getInstance();
    startCalender.setTime(startDate);
    Calendar endCalendar = Calendar.getInstance();
    endCalendar.setTime(endDate);

    for(; startCalender.compareTo(endCalendar)<=0;
          startCalender.add(Calendar.DATE, 1)) {
        // write your main logic here
    }

}
Run Code Online (Sandbox Code Playgroud)


i_a*_*ero 5

我们可以将逻辑迁移到Java 7、Java 8 和 Java 9 的各种方法:

public static List<Date> getDatesRangeJava7(Date startDate, Date endDate) {
    List<Date> datesInRange = new ArrayList<>();
    Calendar startCalendar = new GregorianCalendar();
    startCalendar.setTime(startDate);
    Calendar endCalendar = new GregorianCalendar();
    endCalendar.setTime(endDate);
    while (startCalendar.before(endCalendar)) {
        Date result = startCalendar.getTime();
        datesInRange.add(result);
        startCalendar.add(Calendar.DATE, 1);
    }
    return datesInRange;
}

public static List<LocalDate> getDatesRangeJava8(LocalDate startDate, LocalDate endDate) {
    int numOfDays = (int) ChronoUnit.DAYS.between(startDate, endDate);
    return IntStream.range(0, numOfDays)
            .mapToObj(startDate::plusDays)
            .collect(Collectors.toList());
}

public static List<LocalDate> getDatesRangeJava9(LocalDate startDate, LocalDate endDate) {
    return startDate.datesUntil(endDate).collect(Collectors.toList());
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以调用这些方法:

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date startDate = formatter.parse("2010-12-20");
Date endDate = formatter.parse("2010-12-26");
List<Date> dateRangeList = getDatesRangeJava7(startDate, endDate);
System.out.println(dateRangeList);

LocalDate startLocalDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate endLocalDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
List<LocalDate> dateRangeList8 = getDatesRangeJava8(startLocalDate, endLocalDate);
System.out.println(dateRangeList8);
List<LocalDate> dateRangeList9 = getDatesRangeJava8(startLocalDate, endLocalDate);
System.out.println(dateRangeList9);
Run Code Online (Sandbox Code Playgroud)

输出将是:

[星期一 12 月 20 日 00:00:00 IST 2010,星期二 12 月 21 00:00:00 IST 2010,星期三 12 月 22 00:00:00 IST 2010,星期四 2010 年 12 月 23 日 00:00:00 IST 2010,星期五 12 月 24 日00:00 IST 2010,周六 12 月 25 日 00:00:00 IST 2010]

[2010-12-20, 2010-12-21, 2010-12-22, 2010-12-23, 2010-12-24, 2010-12-25]

[2010-12-20, 2010-12-21, 2010-12-22, 2010-12-23, 2010-12-24, 2010-12-25]

  • 我喜欢 Java 8 和 9 的方式。对于 Java 6 和 7,我建议使用 [the ThreeTen Backport library](https://www.threeten.org/threetenbp/),然后使用与 Java 8 相同的方式。您很好地展示了这种方式如何更清晰,更适合程序员 -友好的。 (3认同)
  • 可怕的`Date` 和`Calendar` 类在几年前被*java.time* 类取代。具体来说,由`Instant` 和`ZonedDateDate` 代替。 (2认同)