Javaで日付の範囲を反復する方法は?


145

スクリプトでは、開始日と終了日を指定して、日付の範囲を介して一連のアクションを実行する必要があります。
Javaを使用してこれを実現するためのガイダンスを教えてください。

for ( currentDate = starDate; currentDate < endDate; currentDate++) {

}

上記のコードは単に不可能であることは知っていますが、私が達成したいことを示すためにそれを行います。


Java 8および9のクリーンアプローチ:stackoverflow.com/a/51942109/1216775
akhil_mittal

回答:


198

さて、具体的にはこの問題のために、Java 8のtime-APIを使用してこのようなことを行うことができますjava.time.LocalDate(またはJava 7以前の同等のJoda Timeクラス)

for (LocalDate date = startDate; date.isBefore(endDate); date = date.plusDays(1))
{
    ...
}

組み込みの/ クラスではなく(またはJoda Time)を使用することを徹底的にお勧めします。java.timeDateCalendar


2
Joda Timeについての要点を拡張します。これを自分で正しく実装しようとすることは、夏時間への変更と夏時間からの変更に関連するまれなケースのため、想像するよりも困難です。
Raedwald 2013年

Jodaの+1、いつか標準のAPIで実現することを願っています。
gyorgyabraham 2013

4
@gyabraham:JSR-310はJava 8でかなり良い状態にあります。–
Jon Skeet

4
このまったく同じコードがJodaの代わりにJava 8のjava.time.LocalDateを使用して機能することを確認できます。
溶融氷

3
Joda-Timeプロジェクトは現在メンテナンスモードであり、java.timeクラスへの移行を推奨しています。コメントで述べたように、このAnswerのコードはjava.timeでそのまま機能しますimport。ステートメントを変更するだけです。
バジルブルク

147

JodaTimeはすばらしいですが、完全を期すため、および/またはAPIが提供する機能を好む場合は、標準のAPIアプローチを以下に示します。

java.util.Date以下のようなインスタンスで開始する場合:

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date startDate = formatter.parse("2010-12-20");
Date endDate = formatter.parse("2010-12-26");

java.util.CalendarJava8をまだ使用していない場合のレガシーアプローチは次のとおりです。

Calendar start = Calendar.getInstance();
start.setTime(startDate);
Calendar end = Calendar.getInstance();
end.setTime(endDate);

for (Date date = start.getTime(); start.before(end); start.add(Calendar.DATE, 1), date = start.getTime()) {
    // Do your job here with `date`.
    System.out.println(date);
}

そしてここにJava8のjava.time.LocalDateアプローチがあります、基本的にはまさにJodaTimeアプローチです:

LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate end = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

for (LocalDate date = start; date.isBefore(end); date = date.plusDays(1)) {
    // Do your job here with `date`.
    System.out.println(date);
}

終了日を含めて反復したい場合は!start.after(end)!date.isAfter(end)それぞれとを使用します。


75

java.timeクラスを使用したJava 8スタイル:

// Monday, February 29 is a leap day in 2016 (otherwise, February only has 28 days)
LocalDate start = LocalDate.parse("2016-02-28"),
          end   = LocalDate.parse("2016-03-02");

// 4 days between (end is inclusive in this example)
Stream.iterate(start, date -> date.plusDays(1))
        .limit(ChronoUnit.DAYS.between(start, end) + 1)
        .forEach(System.out::println);

出力:

2016-02-28
2016-02-29
2016-03-01
2016-03-02

代替:

LocalDate next = start.minusDays(1);
while ((next = next.plusDays(1)).isBefore(end.plusDays(1))) {
    System.out.println(next);
}

Java 9は、datesUntil()メソッドを追加しました。

start.datesUntil(end.plusDays(1)).forEach(System.out::println);

1
複数の値を入力できますか?例:月曜日または木曜日のみ、またはその両方
2017

26

これは基本的にBalusCが出した答えと同じですが、forループの代わりにwhileループを使用すると少し読みやすくなります。

Calendar start = Calendar.getInstance();
start.setTime(startDate);

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

while( !start.after(end)){
    Date targetDay = start.getTime();
    // Do Work Here

    start.add(Calendar.DATE, 1);
}

3
ロジックに「継続」ステートメントが含まれる場合、これは機能しませんが、BalusCのforループバージョンは継続ステートメントで機能します。
Sanjiv Jivan 2014

6

Apache Commons

    for (Date dateIter = fromDate; !dateIter.after(toDate); dateIter = DateUtils.addDays(dateIter, 1)) {
        // ...
    }

+1、私見、これは古いコードで作業しているときに最もクリーンなものです。余分な静的インポートを投入するだけで、addDays(..)さらに短くなります。
Priidu Neemre

4
private static void iterateBetweenDates(Date startDate, Date endDate) {
    Calendar startCalender = Calendar.getInstance();
    startCalender.setTime(startDate);
    Calendar endCalendar = Calendar.getInstance();
    endCalendar.setTime(endDate);

    for(; startCalender.compareTo(endCalendar)<=0;
          startCalender.add(Calendar.DATE, 1)) {
        // write your main logic here
    }

}

3
public static final void generateRange(final Date dateFrom, final Date dateTo)
{
    final Calendar current = Calendar.getInstance();
    current.setTime(dateFrom);

    while (!current.getTime().after(dateTo))
    {
        // TODO

        current.add(Calendar.DATE, 1);
    }
}

3

ロジックをJava 7、Java 8、Java 9のさまざまなメソッドに移行できます。

public static List<Date> getDatesRangeJava7(Date startDate, Date endDate) {
    List<Date> datesInRange = new ArrayList<>();
    Calendar startCalendar = new GregorianCalendar();
    startCalendar.setTime(startDate);
    Calendar endCalendar = new GregorianCalendar();
    endCalendar.setTime(endDate);
    while (startCalendar.before(endCalendar)) {
        Date result = startCalendar.getTime();
        datesInRange.add(result);
        startCalendar.add(Calendar.DATE, 1);
    }
    return datesInRange;
}

public static List<LocalDate> getDatesRangeJava8(LocalDate startDate, LocalDate endDate) {
    int numOfDays = (int) ChronoUnit.DAYS.between(startDate, endDate);
    return IntStream.range(0, numOfDays)
            .mapToObj(startDate::plusDays)
            .collect(Collectors.toList());
}

public static List<LocalDate> getDatesRangeJava9(LocalDate startDate, LocalDate endDate) {
    return startDate.datesUntil(endDate).collect(Collectors.toList());
}

次に、これらのメソッドを次のように呼び出すことができます。

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date startDate = formatter.parse("2010-12-20");
Date endDate = formatter.parse("2010-12-26");
List<Date> dateRangeList = getDatesRangeJava7(startDate, endDate);
System.out.println(dateRangeList);

LocalDate startLocalDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate endLocalDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
List<LocalDate> dateRangeList8 = getDatesRangeJava8(startLocalDate, endLocalDate);
System.out.println(dateRangeList8);
List<LocalDate> dateRangeList9 = getDatesRangeJava8(startLocalDate, endLocalDate);
System.out.println(dateRangeList9);

出力は次のようになります。

[12月20日00:00:00 IST 2010、12月21日火曜日00:00:00 IST 2010、12月22日水曜日00:00:00 IST 2010、12月23日木曜日00:00:00 IST 2010、12月24日金曜日00: 00:00 IST 2010、土12月25日00:00:00 IST 2010]

[2010-12-20、2010-12-21、2010-12-22、2010-12-23、2010-12-24、2010-12-25]

[2010-12-20、2010-12-21、2010-12-22、2010-12-23、2010-12-24、2010-12-25]


1
ひどいクラスDateCalendarクラスは、年も前にjava.timeクラスに取って代わられました。具体的には、Instantおよびに置き換えられましたZonedDateDate
バジルブルク

1
Java 8と9の方法が好きです。Java 6および7の場合は、ThreeTenバックポートライブラリを使用し、Java 8と同じ方法を使用することをお勧めします。この方法が、より明確でプログラマーフレンドリーな方法をうまく示しています。
Ole VV

2

これがJava 8コードです。このコードはあなたの問題を解決すると思います。ハッピーコーディング

    LocalDate start = LocalDate.now();
    LocalDate end = LocalDate.of(2016, 9, 1);//JAVA 9 release date
    Long duration = start.until(end, ChronoUnit.DAYS);
    System.out.println(duration);
     // Do Any stuff Here there after
    IntStream.iterate(0, i -> i + 1)
             .limit(duration)
             .forEach((i) -> {});
     //old way of iteration
    for (int i = 0; i < duration; i++)
     System.out.print("" + i);// Do Any stuff Here

これは、フォローアップできる最善かつ簡単なアプローチです。
jatin Goyal 2016

1

エポックを使用して簡単にループしてみませんか。

long startDateEpoch = new java.text.SimpleDateFormat("dd/MM/yyyy").parse(startDate).getTime() / 1000;

    long endDateEpoch = new java.text.SimpleDateFormat("dd/MM/yyyy").parse(endDate).getTime() / 1000;


    long i;
    for(i=startDateEpoch ; i<=endDateEpoch; i+=86400){

        System.out.println(i);

    }

1

itのようなクラス(イテレータインターフェースを実装)を作成し、それに対して反復することができます。

public class DateIterator implements Iterator<Date>, Iterable<Date>
{

 private Calendar end = Calendar.getInstance();
 private Calendar current = Calendar.getInstance();

 public DateIterator(Date start, Date end)
 {
     this.end.setTime(end);
     this.end.add(Calendar.DATE, -1);
     this.current.setTime(start);
     this.current.add(Calendar.DATE, -1);
 }

 @Override
 public boolean hasNext()
 {
     return !current.after(end);
 }

 @Override
 public Date next()
 {
     current.add(Calendar.DATE, 1);
     return current.getTime();
 }

 @Override
 public void remove()
 {
     throw new UnsupportedOperationException(
        "Cannot remove");
 }

 @Override
 public Iterator<Date> iterator()
 {
     return this;
 }
}

そしてそれを次のように使用します:

Iterator<Date> dateIterator = new DateIterator(startDate, endDate);
while(dateIterator.hasNext()){
      Date selectedDate = dateIterator .next();

}

1

あなたはこれを試すことができます:

OffsetDateTime currentDateTime = OffsetDateTime.now();
for (OffsetDateTime date = currentDateTime; date.isAfter(currentDateTime.minusYears(YEARS)); date = date.minusWeeks(1))
{
    ...
}

0

これにより、30日前に戻り、今日の日付までループすることができます。日付の範囲と方向を簡単に変更できます。

private void iterateThroughDates() throws Exception {
    Calendar start = Calendar.getInstance();
    start.add(Calendar.DATE, -30);
    Calendar end = Calendar.getInstance();
    for (Calendar date = start; date.before(end); date.add(Calendar.DATE, 1))
        {
        System.out.println(date.getTime());
        }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.