Подтвердить что ты не робот

Java 8 LocalDate - Как получить все даты между двумя датами?

Можно ли использовать все даты между двумя датами в новом API java.time?

Скажем, у меня есть эта часть кода:

@Test
public void testGenerateChartCalendarData() {
    LocalDate startDate = LocalDate.now();

    LocalDate endDate = startDate.plusMonths(1);
    endDate = endDate.withDayOfMonth(endDate.lengthOfMonth());
}

Теперь мне нужны все даты между startDate и endDate.

Я думал получить daysBetween двух дат и перебрать:

long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);

for(int i = 0; i <= daysBetween; i++){
    startDate.plusDays(i); //...do the stuff with the new date...
}

Есть ли лучший способ получить даты?

4b9b3361

Ответ 1

Предполагая, что вы в основном хотите перебирать диапазон дат, было бы разумно создать класс DateRange, который является итерируемым. Это позволит вам написать:

for (LocalDate d : DateRange.between(startDate, endDate)) ...

Что-то вроде:

public class DateRange implements Iterable<LocalDate> {

  private final LocalDate startDate;
  private final LocalDate endDate;

  public DateRange(LocalDate startDate, LocalDate endDate) {
    //check that range is valid (null, start < end)
    this.startDate = startDate;
    this.endDate = endDate;
  }

  @Override
  public Iterator<LocalDate> iterator() {
    return stream().iterator();
  }

  public Stream<LocalDate> stream() {
    return Stream.iterate(startDate, d -> d.plusDays(1))
                 .limit(ChronoUnit.DAYS.between(startDate, endDate) + 1);
  }

  public List<LocalDate> toList() { //could also be built from the stream() method
    List<LocalDate> dates = new ArrayList<> ();
    for (LocalDate d = startDate; !d.isAfter(endDate); d = d.plusDays(1)) {
      dates.add(d);
    }
    return dates;
  }
}

Было бы разумно добавлять методы equals и hashcode, getters, возможно, иметь статический factory + private конструктор, чтобы соответствовать стилю кодирования API времени Java и т.д.

Ответ 2

Сначала вы можете использовать TemporalAdjuster для получения последнего дня месяца. Затем API Stream предлагает Stream::iterate, который является правильным инструментом для вашей проблемы.

LocalDate start = LocalDate.now();
LocalDate end = LocalDate.now().plusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
List<LocalDate> dates = Stream.iterate(start, date -> date.plusDays(1))
    .limit(ChronoUnit.DAYS.between(start, end))
    .collect(Collectors.toList());
System.out.println(dates.size());
System.out.println(dates);

Ответ 3

Вы можете использовать .isAfter и .plusDays, чтобы сделать это над циклом. Я бы не сказал лучше, поскольку я не проводил огромных исследований в этой теме, но могу с уверенностью сказать, что он использует API Java 8 и является альтернативой .

LocalDate startDate = LocalDate.now();
LocalDate endDate = startDate.plusMonths(1);
while (!startDate.isAfter(endDate)) {
 System.out.println(startDate);
 startDate = startDate.plusDays(1);
}

Выход

2016-07-05
2016-07-06
...
2016-08-04
2016-08-05

Пример здесь

Ответ 4

Вы можете создать stream объектов LocalDate. У меня тоже была эта проблема, и я опубликовал свое решение как java-timestream на github.

Используя ваш пример...

LocalDateStream
    .from(LocalDate.now())
    .to(1, ChronoUnit.MONTHS)
    .stream()
    .collect(Collectors.toList());

Это более или менее эквивалентно другим предлагаемым здесь решениям, но он заботится обо всех математиках и знает, когда остановиться. Вы можете указать конкретные или относительные даты окончания и указать, сколько времени пропустить каждую итерацию (по умолчанию это один день).

Ответ 5

В свое время библиотека Time4J, я написал оптимизированный разделитель для построения потока дат календаря с хорошими характеристиками распараллеливания. Адаптировано к вашему прецеденту:

LocalDate start = ...;
LocalDate end = ...;

Stream<LocalDate> stream = 
  DateInterval.between(start, end) // closed interval, else use .withOpenEnd()
    .streamDaily()
    .map(PlainDate::toTemporalAccessor);

Этот короткий подход может стать интересной отправной точкой, если вас также интересуют связанные функции, такие как тактовые интервалы в календарную дату (секционированные потоки) или другие функции интервалов, и вы хотите избежать неудобного рукописного кода, см. также API DateInterval.