web-dev-qa-db-ja.com

Java 8 LocalDate-2つの日付の間のすべての日付を取得する方法

新しいJava.time AP​​Iで2つの日付の間のすべての日付を取得する可能性はありますか?

コードのこの部分があるとしましょう:

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

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

ここで、startDateendDateの間のすべての日付が必要です。

2つの日付の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...
}

日付を取得するより良い方法はありますか?

48
Patrick

主に日付範囲を反復処理する場合、反復可能な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メソッド、getterを追加すると、Java time APIなどのコーディングスタイルに一致する静的ファクトリー+プライベートコンストラクターを追加することができます。

66
assylias

最初にTemporalAdjusterを使用して、月の最後の日を取得できます。次にStream AP​​Iは 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);
62
Flown

Java 9

Java 9では、LocalDateクラスが LocalDate.datesUntil(LocalDate endExclusive) メソッドで拡張され、日付範囲内のすべての日付をStream<LocalDate>として返します。

List<LocalDate> dates = startDate.datesUntil(endDate).collect(Collectors.toList());
25
Durgpal Singh

.isAfterおよび.plusDaysを使用して、ループでこれを行うことができます。 betterとは言いませんが、このトピックについては膨大な量の研究を行っていませんが、Java 8 APIを使用しており、 slight代替案。

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

ここの例

9
N.J.Dawson

streamLocalDateオブジェクトを作成できます。私もこの問題を抱えていたので、ソリューションを githubのJavaタイムストリーム として公開しました。

あなたの例を使用して...

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

ここで提案されている他のソリューションとほぼ同等ですが、日付の計算をすべて処理し、いつ停止するかを認識します。特定の終了日または相対的な終了日を指定し、各反復をスキップする時間を指定できます(上記のデフォルトは1日です)。

6
Todd

ThreeTen-Extra ライブラリには LocalDateRange クラスがあり、リクエストしたとおりに実行できます。

LocalDateRange.ofClosed(startDate, endDate).stream()
        .forEach(/* ...do the stuff with the new date... */);
2
M. Justin

tl; dr

Java 9以降で datesUntil からのストリームを使用して、良い Answer by Singh を展開します。

today                                 // Determine your beginning `LocalDate` object.
.datesUntil(                          // Generate stream of `LocalDate` objects.
    today.plusMonths( 1 )             // Calculate your ending date, and ask for a stream of dates till then.
)                                     // Returns the stream.
.collect( Collectors.toList() )       // Collect your resulting dates in a `List`. 
.toString()                           // Generate text representing your found dates.

[2018-09-20、2018-09-21、2018-09-22、2018-09-23、2018-09-24、2018-09-25、2018-09-26、2018-09-27、2018 -09-28、2018-09-29、2018-09-30、2018-10-01、2018-10-02、2018-10-03、2018-10-04、2018-10-05、2018-10 -06、2018-10-07、2018-10-08、2018-10-09、2018-10-10、2018-10-11、2018-10-12、2018-10-13、2018-10-14 、2018-10-15、2018-10-16、2018-10-17、2018-10-18、2018-10-19]

LocalDate::datesUntilストリーム

Java 9以降、日付のストリームを要求できます。 LocalDate::datesUntil を呼び出します。

今日の日付を決定することから始めます。それにはタイムゾーンが必要です。どのような場合でも、日付はゾーンごとに世界中で異なります。

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
LocalDate today = LocalDate.now( z ) ;

終了日を決定します。

LocalDate stop = today.plusMonths( 1 ) ;

開始から終了までの日付のストリームを要求します。

Stream< LocalDate > stream = today.datesUntil( today.plusMonths( 1 ) );

そのストリームから日付を取得し、それらをListに収集します。

List< LocalDate > datesForMonthFromToday = stream.collect( Collectors.toList() );

日付のリストを印刷して、標準 ISO 8601 形式のテキストを生成します。

System.out.println( datesForMonthFromToday );

Java.timeについて

Java.time フレームワークは、Java 8以降に組み込まれています。これらのクラスは、 Java.util.DateCalendar 、& SimpleDateFormat などの厄介な古い legacy date-timeクラスに取って代わります。

Joda-Time プロジェクトは、現在 メンテナンスモード であり、 Java.time クラスへの移行を推奨しています。

詳細については、 Oracle Tutorial を参照してください。また、Stack Overflowで多くの例と説明を検索してください。仕様は JSR 31 です。

Java.timeオブジェクトをデータベースと直接交換できます。 JDBC 4.2 以降に準拠する JDBCドライバー を使用します。文字列もJava.sql.*クラスも必要ありません。

Java.timeクラスはどこで入手できますか?

ThreeTen-Extra プロジェクトは、Java.timeを追加のクラスで拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある証明の場です。 IntervalYearWeekYearQuarter 、および more

1
Basil Bourque

Googleの Guava ライブラリで Range 機能を使用できます。 DiscreteDomain over LocalDateインスタンスを定義すると、範囲内のすべての日付の ContiguousSet を取得できます。

LocalDate d1 = LocalDate.parse("2017-12-25");
LocalDate d2 = LocalDate.parse("2018-01-05");

DiscreteDomain<LocalDate> localDateDomain = new DiscreteDomain<LocalDate>() {
    public LocalDate next(LocalDate value) { return value.plusDays(1); }
    public LocalDate previous(LocalDate value) { return value.minusDays(1); }
    public long distance(LocalDate start, LocalDate end) { return start.until(end, ChronoUnit.DAYS); }
    public LocalDate minValue() { return LocalDate.MIN; }
    public LocalDate maxValue() { return LocalDate.MAX; }
};

Set<LocalDate> datesInRange = ContiguousSet.create(Range.closed(d1, d2), localDateDomain);
1
M. Justin

私のタイムライブラリ Time4J では、並列化の特性が良好なカレンダー日付のストリームを構築するための最適化されたスプリッターを作成しました。ユースケースに適応:

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

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

カレンダーの日付ごとのクロック間隔(パーティションストリーム)やその他の間隔機能などの関連機能にも興味があり、厄介な手書きコードを避けたい場合、この短いアプローチは興味深い出発点になります。 DateInterval

1
Meno Hochschild