如何在Java中获取两个日期之间的日期列表

88
  • 我需要一个包括起始日期和结束日期在内的日期列表。
  • 结果应该是一个包含所有日期的列表,包括起始日期和结束日期。

1
LocalDate.datesUntil() - ZhekaKozlov
1
对于那些使用Groovy(使用LocalDate)的人:(fromDate..toDate).each { println it } - lepe
24个回答

58

java.time包

如果您正在使用Java 8,那么有一种更加简洁的方法。Java 8中的新java.time包包含了Joda-Time API的功能。

您可以使用以下代码来满足您的需求:

String s = "2014-05-01";
String e = "2014-05-10";
LocalDate start = LocalDate.parse(s);
LocalDate end = LocalDate.parse(e);
List<LocalDate> totalDates = new ArrayList<>();
while (!start.isAfter(end)) {
    totalDates.add(start);
    start = start.plusDays(1);
}

顺便提一下,对于那些无法转移到Java 8的人来说,使用Joda-Time库可以使用完全相同的代码。虽然java.time不能完全替代Joda-Time,但在这种特定情况下,代码恰好是相同的。 - Basil Bourque
您可以通过将经过的天数传递给ArrayList构造函数来设置列表的初始容量。 int initialCapacity = java.lang.Math.toIntExact( ChronoUnit.DAYS.between( start , end ) ) ; - Basil Bourque
3
请注意,Java 9通过Stream<LocalDate>使得使用LocalDate更加容易,从而消除了构建自己的while循环的需要。请参阅Hochschild的答案 - Basil Bourque
如果我想使用它来查找并分离工作日和周末,该怎么做?我该怎么做? - justarandomguy
LocalDate有一个获取DayOfWeek的方法。请查看一下。 - Yadu Krishnan

54

2010年,我建议使用Joda-Time

请注意,Joda-Time现在处于维护模式。自1.8(2014年)以来,您应该使用java.time

逐天添加一天,直到达到结束日期:

int days = Days.daysBetween(startDate, endDate).getDays();
List<LocalDate> dates = new ArrayList<LocalDate>(days);  // Set initial capacity to `days`.
for (int i=0; i < days; i++) {
    LocalDate d = startDate.withFieldAdded(DurationFieldType.days(), i);
    dates.add(d);
}

你自己编写一个迭代器来实现这个功能也并不难,而且会更好。


1
请参考同一问题下 Krishnan 的回答:[https://dev59.com/r3E85IYBdhLWcg3wnU6p#23932946],以获取其他解决方案。 - Basil Bourque
14
使用plusDays函数来简化该代码。因此,将LocalDate d = startDate.withFieldAdded(DurationFieldType.days(), i);改为LocalDate d = startDate.plusDays(i); - Basil Bourque
FYI,Joda-Time 项目现已进入维护模式,团队建议迁移到java.time类。请参阅Oracle的教程 - Basil Bourque
该列表不包含结束日期,请将 i < days 更改为 i <= days。 - tutak
有人可以使用当前的java.time api更新它吗?它一直让人感到困惑(他们在2019年仍然提出jodatime的问题)。 - Andrey Tyukin

46
获取两个日期之间相差的天数,包括起始和结束日期。
public static List<Date> getDaysBetweenDates(Date startdate, Date enddate)
{
    List<Date> dates = new ArrayList<Date>();
    Calendar calendar = new GregorianCalendar();
    calendar.setTime(startdate);

    while (calendar.getTime().before(enddate))
    {
        Date result = calendar.getTime();
        dates.add(result);
        calendar.add(Calendar.DATE, 1);
    }
    return dates;
}

3
通常情况下,当您使用before()方法(相当于<操作符)时,最终列表将不包括“fechaFinal”(结束日期)。应该使用<=操作符。由于Calendar类中没有相应的方法,因此应适当增加结束日期。 - Alex Semeniuk
将结束日期增加1并不提供完整的解决方案,除非我们将enddate的时间信息重置为0。 - Saurabh Mishra
1
如果使用午夜作为“enddate”,最后一天将不会显示出来。比较自纪元以来的时间可以解决这个问题:while (calendar.getTime().getTime() <= enddate.getTime()) - Ricardo Teixeira
请注意,像java.util.Datejava.util.Calendarjava.text.SimpleDateFormat这样的老旧日期时间类现在已经成为遗留系统,被内置于Java 8及更高版本中的java.time类所取代。请参阅Oracle的教程 - Basil Bourque

35

流(Streams)

编辑:Joda-Time现已过时,将答案更改为使用Java 8。

以下是使用流(streams)的Java 8方法。

List<LocalDate> daysRange = Stream.iterate(startDate, date -> date.plusDays(1)).limit(numOfDays).collect(Collectors.toList());

5
numofDays 可以通过以下方式获取:long numofDays = ChronoUnit.DAYS.between(startDate, endDate)。 - Chetan Sharma
1
如果您正在使用Java 8及更高版本,则无需使用Joda-Time库。Joda-Time项目现在处于维护模式,团队建议迁移到Java 8及更高版本中内置的java.time类。请参见Oracle的教程。请参见Hochschild的答案 - Basil Bourque
为什么我需要在numOfDays上加1,才能将endDate添加到列表中? - pipilam
@pipilam,你不需要将+1添加到numOfDays中,而是需要将1添加到你正在迭代的日期上。 - Amit Goldstein

17

请查看以下代码:

List<Date> dates = new ArrayList<Date>();

String str_date ="27/08/2010";
String end_date ="02/09/2010";

DateFormat formatter ; 

formatter = new SimpleDateFormat("dd/MM/yyyy");
Date  startDate = (Date)formatter.parse(str_date); 
Date  endDate = (Date)formatter.parse(end_date);
long interval = 24*1000 * 60 * 60; // 1 hour in millis
long endTime =endDate.getTime() ; // create your endtime here, possibly using Calendar or Date
long curTime = startDate.getTime();
while (curTime <= endTime) {
    dates.add(new Date(curTime));
    curTime += interval;
}
for(int i=0;i<dates.size();i++){
    Date lDate =(Date)dates.get(i);
    String ds = formatter.format(lDate);    
    System.out.println(" Date is ..." + ds);
}

输出:

日期为...27/08/2010
日期为...28/08/2010
日期为...29/08/2010
日期为...30/08/2010
日期为...31/08/2010
日期为...01/09/2010
日期为...02/09/2010


2
由于夏令时结束那天有25个小时,所以这种方法在那天行不通。你会得到下一天的重复。德国的例子:日期是...30/10/2010 | 日期是...31/10/2010 | 日期是...31/10/2010 | 日期是...01/11/2010(简单解决方案:将开始日期加上一些小时(12))。 - user85421

12

推荐日期流

Java 9 中,您可以使用以下新方法:LocalDate::datesUntil

LocalDate start = LocalDate.of(2017, 2, 1);
LocalDate end = LocalDate.of(2017, 2, 28);

Stream<LocalDate> dates = start.datesUntil(end.plusDays(1));
List<LocalDate> list = dates.collect(Collectors.toList());
新方法datesUntil(...)使用独占结束日期,因此需要使用显示处理来添加一天。
一旦您获得了流,就可以利用java.util.streamjava.util.function包提供的所有功能。与基于自定义for-或while循环的早期方法相比,使用流的工作变得非常简单。
或者,如果您正在寻找默认情况下操作包含日期但也可以以其他方式配置的基于流的解决方案,则可能会发现我在库Time4J中的类DateInterval非常有趣,因为它提供了许多围绕日期流的特殊功能,包括一个效率高于Java-9的性能分裂器。
PlainDate start = PlainDate.of(2017,  2, 1);
PlainDate end = start.with(PlainDate.DAY_OF_MONTH.maximized());
Stream<PlainDate> stream = DateInterval.streamDaily(start, end);

对于整月来说,甚至更简单:

Stream<PlainDate> februaryDates = CalendarMonth.of(2017, 2).streamDaily();
List<LocalDate> list = 
    februaryDates.map(PlainDate::toTemporalAccessor).collect(Collectors.toList());

5

使用Java 8

public Stream<LocalDate> getDaysBetween(LocalDate startDate, LocalDate endDate) {
    return IntStream.range(0, (int) DAYS.between(startDate, endDate)).mapToObj(startDate::plusDays);
}

1
我发现这是最好的解决方案,你可以使用LongStream而不是IntStream来避免强制转换。 - Ivan Perales M.

4

类似这样的代码一定可以运行:

private List<Date> getListOfDaysBetweenTwoDates(Date startDate, Date endDate) {
    List<Date> result = new ArrayList<Date>();
    Calendar start = Calendar.getInstance();
    start.setTime(startDate);
    Calendar end = Calendar.getInstance();
    end.setTime(endDate);
    end.add(Calendar.DAY_OF_YEAR, 1); //Add 1 day to endDate to make sure endDate is included into the final list
    while (start.before(end)) {
        result.add(start.getTime());
        start.add(Calendar.DAY_OF_YEAR, 1);
    }
    return result;
}

3
 public static List<Date> getDaysBetweenDates(Date startDate, Date endDate){
        ArrayList<Date> dates = new ArrayList<Date>();
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(startDate);

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

        while(cal1.before(cal2) || cal1.equals(cal2))
        {
            dates.add(cal1.getTime());
            cal1.add(Calendar.DATE, 1);
        }
        return dates;
    }

可怕的“Calendar”类现在已经过时,随着JSR 310的采用,被现代的java.time类所取代。 - Basil Bourque

3

使用 Lamma,在Java中可以这样写:

    for (Date d: Dates.from(2014, 6, 29).to(2014, 7, 1).build()) {
        System.out.println(d);
    }

输出结果为:

    Date(2014,6,29)
    Date(2014,6,30)
    Date(2014,7,1)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接