Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build a list of LocalDate from a given range? [duplicate]

I have the following method, where I have the startDate and the endDate of type String yyyy/mm/dd. I want to return a List<LocalDate>

protected List<LocalDate> getDateList(String startDate, String endDate) {

//build list here

}

How can I do this in Java 8?

like image 703
kosta Avatar asked Nov 18 '16 07:11

kosta


2 Answers

Assuming that your input data is correct, we could use a Stream API to generate all dates in the given range:

final LocalDate start = LocalDate.parse(startDate, DateTimeFormatter.ofPattern("yyyy/MM/dd"));
final LocalDate end = LocalDate.parse(endDate, DateTimeFormatter.ofPattern("yyyy/MM/dd"));

final int days = (int) start.until(end, ChronoUnit.DAYS);

return Stream.iterate(start, d -> d.plusDays(1))
  .limit(days)
  .collect(Collectors.toList());

Example:

getDateList("2012/10/10", "2012/10/12")

[2012-10-10, 2012-10-11]

If you want to include the ending date, you need to use .limit(days + 1).


Since Java 9, it's possible to simplify this to:

Stream.iterate(start, d -> d.isBefore(end), d -> d.plusDays(1))
  .collect(Collectors.toList());

or even:

start.datesUntil(end, Period.ofDays(1));

Just remember to make sure that the inclusion of the last date is handled properly.

like image 145
Grzegorz Piwowarek Avatar answered Oct 27 '22 01:10

Grzegorz Piwowarek


The accepted answer is correct and a good one.

However, there is an alternative solution where we create a LongStream over the number of days. Here rangeClosed() makes sure to create a stream of longs which include the last day. Replace with range() if the final day should not be included in the list.

The advantage of doing this, compared to the solution proposed by pivovarit, is that we do not need to downcast the long to an int. Also, since we can use either rangeClosed() or range(), we don't need the days + 1 trick to include/exclude the last date:

public List<LocalDate> toDateList(String startDate, String endDate) {
  final LocalDate start = LocalDate.parse(startDate, DateTimeFormatter.ofPattern("yyyy/MM/dd"));
  final LocalDate end = LocalDate.parse(endDate, DateTimeFormatter.ofPattern("yyyy/MM/dd"));

  final long days = start.until(end, ChronoUnit.DAYS);

  return LongStream.rangeClosed(0, days)
      .mapToObj(start::plusDays)
      .collect(Collectors.toList());
}
like image 39
Magnilex Avatar answered Oct 26 '22 23:10

Magnilex