Wie kann ich in Java durch verschiedene Datumsbereiche iterieren?


144

In meinem Skript muss ich eine Reihe von Aktionen über verschiedene Datumsbereiche hinweg ausführen, wobei ein Start- und ein Enddatum angegeben werden.
Bitte geben Sie mir eine Anleitung, um dies mit Java zu erreichen.

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

}

Ich weiß, dass der obige Code einfach unmöglich ist, aber ich mache es, um Ihnen zu zeigen, was ich erreichen möchte.


Java 8 und 9 sauberer Ansatz: stackoverflow.com/a/51942109/1216775
akhil_mittal

Antworten:


198

Nun, Sie könnten so etwas mit der Zeit-API von Java 8 tun, speziell für dieses Problem java.time.LocalDate(oder den entsprechenden Joda-Zeitklassen für Java 7 und älter).

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

Ich würde gründlich mit empfehlen java.time(oder Joda Time) über die eingebauten in Date/ CalendarKlassen.


2
Um auf den Punkt über Joda Time einzugehen: Es ist schwieriger, dies selbst richtig umzusetzen, als man denkt, da es sich um Änderungen in der Sommerzeit handelt.
Raedwald

+1 für Joda, ich hoffe, dass es eines Tages sein Land in der Standard-API erreichen wird.
Gyorgyabraham

4
@gyabraham: JSR-310 sieht in einer ziemlich guten Form für Java 8 aus.
Jon Skeet

4
Kann bestätigen, dass genau derselbe Code mit java.time.LocalDate von Java 8 anstelle von Joda funktioniert.
Geschmolzenes Eis

3
Das Joda-Time-Projekt befindet sich jetzt im Wartungsmodus und empfiehlt die Migration zu den Klassen java.time. Wie in den Kommentaren erwähnt, funktioniert der Code dieser Antwort in java.time unverändert. Ändern Sie einfach Ihre importAnweisungen.
Basil Bourque

146

JodaTime ist jedoch der Vollständigkeit halber und / oder wenn Sie API-bereitgestellte Funktionen bevorzugen, nett. Hier sind die Standard-API-Ansätze.

Wenn Sie mit java.util.DateInstanzen wie den folgenden beginnen:

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

Hier ist der Legacy- java.util.CalendarAnsatz für den Fall, dass Sie noch nicht mit Java8 arbeiten:

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);
}

Und hier ist der java.time.LocalDateAnsatz von Java8 , im Grunde genau der JodaTime-Ansatz:

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);
}

Wenn Sie möchten , zu Iterierte inklusive das Enddatum, dann verwenden !start.after(end)und !date.isAfter(end)jeweils.


75

Java 8- Stil unter Verwendung der Klassen java.time :

// 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);

Ausgabe:

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

Alternative:

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

Java 9 hat die Methode DatumsUntil () hinzugefügt :

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

1
Können Sie mehrere Werte setzen? Zum Beispiel: nur Montag oder Donnerstag oder beides
Lieferung

26

Dies ist im Wesentlichen die gleiche Antwort, die BalusC gegeben hat, jedoch mit einer while-Schleife anstelle einer for-Schleife etwas besser lesbar:

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
Dies funktioniert nicht, wenn die Logik "continue" -Anweisungen umfasst, während die for-Schleifenversion von BalusC mit continue-Anweisungen funktioniert.
Sanjiv Jivan

6

Apache Commons

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

+1, IMHO, dies ist die sauberste, wenn Sie mit altem Code arbeiten. Werfen Sie einfach einen zusätzlichen statischen Import für addDays(..)und es wird noch kürzer.
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

Wir können die Logik auf verschiedene Methoden für Java 7, Java 8 und Java 9 migrieren :

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());
}

Dann können wir diese Methoden aufrufen als:

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);

Die Ausgabe wäre:

[Mo 20 Dez 00:00:00 IST 2010, Di 21 Dez 00:00:00 IST 2010, Mi 22 Dez 00:00:00 IST 2010, Do 23 Dez 00:00:00 IST 2010, Fr 24 Dez 00: 00:00 IST 2010, Sa 25 Dez 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
Das Schreckliche Dateund der CalendarUnterricht wurden vor Jahren durch den Java.time- Unterricht ersetzt. Insbesondere ersetzt durch Instantund ZonedDateDate.
Basil Bourque

1
Ich mag die Java 8 und 9 Wege. Für Java 6 und 7 empfehle ich die Verwendung der ThreeTen Backport-Bibliothek und dann auf die gleiche Weise wie in Java 8. Sie zeigen gut, wie dieser Weg klarer und programmiererfreundlicher ist.
Ole VV

2

Hier ist Java 8-Code. Ich denke, dieser Code wird Ihr Problem lösen. Viel Spaß beim Codieren

    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

Dies ist der beste und einfachste Ansatz, den Sie verfolgen können.
Jatin Goyal

1

Warum nicht Epoche benutzen und einfach durchschleifen?

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

Sie können eine Klasse wie diese schreiben (Iterator-Schnittstelle implementieren) und darüber iterieren.

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;
 }
}

und benutze es wie:

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

}

1

Sie können dies versuchen:

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

0

Auf diese Weise können Sie 30 Tage zurück beginnen und bis zum heutigen Datum durchlaufen. Sie können den Datums- und Richtungsbereich leicht ändern.

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());
        }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.