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


Answers:


52

早在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)对此问题的答案
罗勒·布尔克

12
提示通过调用来简化该代码plusDays。因此,这LocalDate d = startDate.withFieldAdded(DurationFieldType.days(), i);becames本LocalDate d = startDate.plusDays(i);
罗勒布尔克

仅供参考,Joda-Time项目现在处于维护模式,团队建议迁移到java.time类。请参见Oracle教程
罗勒·布尔克

该列表不包含结束日期,
请将

有人可以用当前的java.time api更新它吗?它使人们感到困惑(他们在2019年不断提出关于jodatime的问题)。
安德烈(Andrey Tyukin)

47

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,但在这种特殊情况下,代码恰好是相同的。
罗勒·布尔克

您可以通过向ArrayList构造函数传递经过的天数来设置列表的初始容量。int initialCapacity = java.lang.Math.toIntExact( ChronoUnit.DAYS.between( start , end ) ) ;
罗勒·布尔克

2
请注意,Java 9通过使其LocalDate更容易使用Stream<LocalDate>,从而消除了构建自己的while循环的需要。请参阅Hochschild的答案
罗勒·布尔克

如果我想使用此方法查找并分开工作日和周末怎么办?我该怎么做?
justarandom

LocalDate有一种获取DayOfWeek的方法。检查出。
Yadu Krishnan

41

获取日期之间的天数(含)。

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
通常情况下,fechaFinal使用before()方法(等于<操作)时,最终列表将不包含(结束日期)。而是应使用<=操作。由于Calendar课堂上没有等效的方法,因此您应该稍微增加结束日期。
Alex Semeniuk

在将结束日期的时间信息重置为0之前,将结束日期增加1不会提供完整的证明解决方案
Saurabh Mishra 2015年

1
如果使用午夜作为enddate最后一天,则不会显示。比较时代以来的时间将解决此问题: while (calendar.getTime().getTime() <= enddate.getTime())
里卡多·特谢拉

仅供参考,麻烦的旧日期,时间类,如java.util.Datejava.util.Calendarjava.text.SimpleDateFormat现在的遗产,由取代java.time内置到Java 8和更高等级。请参见Oracle教程
罗勒·布尔克

27

编辑:现在不推荐使用Joda-Time,将答案改为使用Java 8。

这是使用流的Java 8方法。

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

2
numofDays可以找到,因为long numofDays = ChronoUnit.DAYS.between(startDate,endDate);
Chetan Sharma

1
如果您使用的是Java 8和更高版本,则无需使用Joda-Time库。该乔达时间的项目现在处于维护模式,与团队的建议迁移java.time内置到Java 8和更高等级。请参见Oracle教程。请参阅Hochschild答案
罗勒·布尔克

为什么我需要为numOfDays添加+1才能将endDate也加入列表?
pipilam

@pipilam,您没有在numOfDays上加+1,而是在迭代的当天加1
Amit Goldstein

16

请找到以下代码。

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 2010年

6

推荐日期流

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(...)的结束日期不限,因此所示的hack增加了一天。

一旦获得流,就可以利用java.util.stream-或java.util.function-packages提供的所有功能。与基于自定义的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.19年

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

使用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)

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类现在是传统的,由现代所取代java.time班,通过JSR 310
罗勒布尔克

2

一种解决方案是创建一个Calendar实例,然后开始一个周期,增加其Calendar.DATE字段直到达到所需的日期。同样,在每个步骤上,您都应该创建一个Date实例(具有相应的参数),并将其放入列表中。

一些肮脏的代码:

    public List<Date> getDatesBetween(final Date date1, final Date date2) {
    List<Date> dates = new ArrayList<Date>();

    Calendar calendar = new GregorianCalendar() {{
        set(Calendar.YEAR, date1.getYear());
        set(Calendar.MONTH, date1.getMonth());
        set(Calendar.DATE, date1.getDate());
    }};

    while (calendar.get(Calendar.YEAR) != date2.getYear() && calendar.get(Calendar.MONTH) != date2.getMonth() && calendar.get(Calendar.DATE) != date2.getDate()) {
        calendar.add(Calendar.DATE, 1);
        dates.add(new Date(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DATE)));
    }

    return dates;
}

1
您知道使用不赞成使用的API吗?是的,Java日期处理很糟糕。
Extraneon 2010年

我认为
这段

1

您也可以查看Date.getTime() API。这样就可以添加一个增量。然后创建一个新的日期。

List<Date> dates = new ArrayList<Date>();
long interval = 1000 * 60 * 60; // 1 hour in millis
long endtime = ; // create your endtime here, possibly using Calendar or Date
long curTime = startDate.getTime();
while (curTime <= endTime) {
  dates.add(new Date(curTime));
  curTime += interval;
}

也许Apache Commons在DateUtils中有类似的东西,或者他们也有CalendarUtils :)

编辑

如果间隔不完美,则可能无法包括开始日期和结束日期:)


1
List<Date> dates = new ArrayList<Date>();
String str_date = "DD/MM/YYYY";
String end_date = "DD/MM/YYYY";
DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
Date startDate = (Date)formatter.parse(str_date); 
Date endDate = (Date)formatter.parse(end_date);
long interval = 1000 * 60 * 60; // 1 hour in milliseconds
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);
    //Write your code for storing dates to list
}

1

就像@folone一样,但是正确

private static List<Date> getDatesBetween(final Date date1, final Date date2) {
    List<Date> dates = new ArrayList<>();
    Calendar c1 = new GregorianCalendar();
    c1.setTime(date1);
    Calendar c2 = new GregorianCalendar();
    c2.setTime(date2);
    int a = c1.get(Calendar.DATE);
    int b = c2.get(Calendar.DATE);
    while ((c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR)) || (c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH)) || (c1.get(Calendar.DATE) != c2.get(Calendar.DATE))) {
        c1.add(Calendar.DATE, 1);
        dates.add(new Date(c1.getTimeInMillis()));
    }
    return dates;
}

您为什么不使用before()after()方法来比较两个Calendar实例?
Alex Semeniuk

1

使用Joda-Time,可能会更好:

LocalDate dateStart = new LocalDate("2012-01-15");
LocalDate dateEnd = new LocalDate("2012-05-23");
// day by day:
while(dateStart.isBefore(dateEnd)){
    System.out.println(dateStart);
    dateStart = dateStart.plusDays(1);
}

这是我的解决方案...。非常简单:)


1
仅供参考,如果compareTo您不使用,则该代码可能更具可读性dateStart.isBefore( dateEnd )
罗勒·布尔克2014年

1

这是获取日期列表的简单解决方案

import java.io.*;
import java.util.*;
import java.text.SimpleDateFormat;  
public class DateList
{

public static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

 public static void main (String[] args) throws java.lang.Exception
 {

    Date dt = new Date();
    System.out.println(dt);

        List<Date> dates = getDates("2017-01-01",dateFormat.format(new Date()));
        //IF you don't want to reverse then remove Collections.reverse(dates);
         Collections.reverse(dates);
        System.out.println(dates.size());
    for(Date date:dates)
    {
        System.out.println(date);
    }
 }
 public static List<Date> getDates(String fromDate, String toDate)
 {
    ArrayList<Date> dates = new ArrayList<Date>();

    try {

        Calendar fromCal = Calendar.getInstance();
        fromCal.setTime(dateFormat .parse(fromDate));

        Calendar toCal = Calendar.getInstance();
        toCal.setTime(dateFormat .parse(toDate));

        while(!fromCal.after(toCal))
        {
            dates.add(fromCal.getTime());
            fromCal.add(Calendar.DATE, 1);
        }


    } catch (Exception e) {
        System.out.println(e);
    }
    return dates;
 }
}

仅供参考,麻烦的旧日期,时间类,如java.util.Datejava.util.Calendarjava.text.SimpleTextFormat现在的遗产,由取代java.time类。请参见Oracle教程。这项工作是运用现代类更容易实现。
罗勒·布尔克

0

尾递归版本:

public static void datesBetweenRecursive(Date startDate, Date endDate, List<Date> dates) {
    if (startDate.before(endDate)) {
        dates.add(startDate);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        calendar.add(Calendar.DATE, 1);
        datesBetweenRecursive(calendar.getTime(), endDate, dates);
    }
}

与朱尔斯·罗杰森(Jules Rogerson)的相同,但递归而不是迭代
Lluis Martinez

0

增强上述解决方案之一。由于有时会在结束日期前增加1天,因此会在结束日期后增加一天。

    公共静态列表getDaysBetweenDates(日期开始日期,日期结束日期)
    {
        列出日期= new ArrayList();
        日历startDay = new GregorianCalendar();
        calendar.setTime(startdate);
        日历endDay = new GregorianCalendar();
        endDay.setTime(enddate);
        endDay.add(Calendar.DAY_OF_YEAR,1);
        endDay.set(Calendar.HOUR_OF_DAY,0);
        endDay.set(Calendar.MINUTE,0);
        endDay.set(Calendar.SECOND,0);
        endDay.set(Calendar.MILLISECOND,0);

        while(calendar.getTime()。before(endDay.getTime())){
            日期结果= startDay.getTime();
            date.add(result);
            startDay.add(Calendar.DATE,1);
        }
        返回日期;
    }


0

这是我获取两个日期之间的日期的方法,包括/包括工作日在内。它还将源和所需日期格式作为参数。

public static List<String> getAllDatesBetweenTwoDates(String stdate,String enddate,String givenformat,String resultformat,boolean onlybunessdays) throws ParseException{
        DateFormat sdf;
        DateFormat sdf1;
        List<Date> dates = new ArrayList<Date>();
        List<String> dateList = new ArrayList<String>();
          SimpleDateFormat checkformat = new SimpleDateFormat(resultformat); 
          checkformat.applyPattern("EEE");  // to get Day of week
        try{
            sdf = new SimpleDateFormat(givenformat);
            sdf1 = new SimpleDateFormat(resultformat);
            stdate=sdf1.format(sdf.parse(stdate));
            enddate=sdf1.format(sdf.parse(enddate));

            Date  startDate = (Date)sdf1.parse( stdate); 
            Date  endDate = (Date)sdf1.parse( enddate);
            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 = sdf1.format(lDate);   
                if(onlybunessdays){
                    String day= checkformat.format(lDate); 
                    if(!day.equalsIgnoreCase("Sat") && !day.equalsIgnoreCase("Sun")){
                          dateList.add(ds);
                    }
                }else{
                      dateList.add(ds);
                }

                //System.out.println(" Date is ..." + ds);

            }


        }catch(ParseException e){
            e.printStackTrace();
            throw e;
        }finally{
            sdf=null;
            sdf1=null;
        }
        return dateList;
    }

方法调用将类似于:

public static void main(String aregs[]) throws Exception {
        System.out.println(getAllDatesBetweenTwoDates("2015/09/27","2015/10/05","yyyy/MM/dd","dd-MM-yyyy",false));
    }

您可以找到演示代码:单击此处


0
List<LocalDate> totalDates = new ArrayList<>();
popularDatas(startDate, endDate, totalDates);
System.out.println(totalDates);

private void popularDatas(LocalDate startDate, LocalDate endDate, List<LocalDate> datas) {
    if (!startDate.plusDays(1).isAfter(endDate)) {
        popularDatas(startDate.plusDays(1), endDate, datas);
    } 
    datas.add(startDate);
}

递归解决方案


0

这将添加两个日期之间的所有日期,并将添加当前日期,然后根据循环条件添加新日期。

private void onDateSet(){
    Calendar endDate = Calendar.getInstance(),startDate = Calendar.getInstance();
    startDate.set(currentYear,currentMonthOfYear,currentDayOfMonth);
    endDate.set(inputYear,inputMonthOfYear,inputDayOfMonth);
    datesToAdd(startDate,endDate);
    }

    //call for get dates list
    private List<Date> datesToAdd(Calendar startDate,Calendar endDate){
                    List<Dates> datesLists = new List<>();
                    while (startDate.get(Calendar.YEAR) != endDate.get(Calendar.YEAR) ||   
                           startDate.get(Calendar.MONTH) != endDate.get(Calendar.MONTH) ||
                           startDate.get(Calendar.DAY_OF_MONTH) != endDate.get(Calendar.DAY_OF_MONTH)) {

                             datesList.add(new Date(startDate.get(Calendar.YEAR), startDate.get(Calendar.MONTH), startDate.get(Calendar.DATE));

                             startDate.add(Calendar.DATE, 1);//increas dates

                         }
                         return datesList;
                }

仅供参考,此代码使用麻烦的旧日期时间类,这些类现在已被遗留,由java.time类取代。
罗勒·布尔克

我没有使用java.time类。我使用import java.util.Calendar; 导入java.util.Date; 我正在使用Java 8,一切都正常工作。
ankurdayalsingh

千万不能使用CalendarDate现在,它们已被java.time类替换。那些旧类令人困惑,设计欠佳且存在缺陷。Sun,Oracle和JCP社区都同意用java.time类替换这些旧类。参见JSR 310。建议,DateCalendar在2017年是不明智的。
罗勒·布尔克

-1

您可以像这样计算java9功能

public  List<LocalDate> getDatesBetween (
 LocalDate startDate, LocalDate endDate) {

   return startDate.datesUntil(endDate)
     .collect(Collectors.toList());
}
`` 



Hochschild的答案已经涵盖了该解决方案。
罗勒·布尔克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.