Làm thế nào để lặp lại thông qua phạm vi Ngày trong Java?


144

Trong kịch bản của tôi, tôi cần thực hiện một tập hợp các hành động thông qua phạm vi ngày, đưa ra ngày bắt đầu và ngày kết thúc.
Vui lòng cung cấp cho tôi hướng dẫn để đạt được điều này bằng cách sử dụng Java.

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

}

Tôi biết đoạn mã trên đơn giản là không thể, nhưng tôi làm nó để cho bạn thấy những gì tôi muốn đạt được.


Cách tiếp cận sạch Java 8 và 9: stackoverflow.com/a/51942109/1216775
akhil_mittal

Câu trả lời:


198

Chà, bạn có thể làm một cái gì đó như thế này bằng cách sử dụng API thời gian của Java 8 , cụ thể cho vấn đề này java.time.LocalDate(hoặc các lớp Thời gian Joda tương đương cho Java 7 trở lên)

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

Tôi hoàn toàn khuyên bạn nên sử dụng java.time(hoặc Joda Time) trên các lớp Date/ tích hợp Calendar.


2
Để mở rộng quan điểm về Thời gian của Joda: cố gắng tự thực hiện chính xác điều này khó hơn người ta có thể nghĩ vì các trường hợp góc xung quanh thay đổi đến và từ thời điểm mùa hè.
Raedwald

+1 cho Joda, tôi hy vọng một ngày nào đó nó sẽ đạt được mục tiêu trong API tiêu chuẩn.
gyorgyabraham

4
@gyabraham: JSR-310 đang tìm kiếm một hình dạng khá tốt cho Java 8.
Jon Skeet

4
Có thể xác nhận chính xác mã này sẽ hoạt động bằng cách sử dụng java.time.LocalDate của Java 8 thay vì Joda.
Băng nóng chảy

3
Dự án Joda-Time hiện đang ở chế độ bảo trì và khuyên bạn nên di chuyển sang các lớp java.time. Như đã đề cập trong các nhận xét, mã Trình trả lời này hoạt động như trong java.time, chỉ cần thay đổi các importcâu lệnh của bạn .
Basil Bourque

146

Tuy nhiên, JodaTime là tốt vì mục đích hoàn chỉnh và / hoặc nếu bạn thích các cơ sở cung cấp API, đây là các cách tiếp cận API tiêu chuẩn.

Khi bắt đầu với các java.util.Datetrường hợp như dưới đây:

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

Đây là java.util.Calendarcách tiếp cận kế thừa trong trường hợp bạn chưa có trên Java8:

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

Và đây là java.time.LocalDatecách tiếp cận của Java8 , về cơ bản chính xác là cách tiếp cận 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);
}

Nếu bạn muốn lặp lại bao gồm ngày kết thúc, sau đó sử dụng !start.after(end)!date.isAfter(end)tương ứng.


75

Kiểu Java 8 , sử dụng các lớp 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);

Đầu ra:

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

Thay thế:

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

Java 9 đã thêm phương thức dateUntil () :

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

1
bạn có thể đặt nhiều giá trị? ví dụ: chỉ thứ hai hoặc thứ năm hoặc cả hai
delive

26

Đây thực chất là cùng một câu trả lời mà BalusC đã đưa ra, nhưng dễ đọc hơn một chút với vòng lặp while thay cho vòng lặp for:

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
Điều này sẽ không hoạt động nếu logic liên quan đến các câu lệnh "tiếp tục", trong khi phiên bản vòng lặp for của BalusC hoạt động với các câu lệnh tiếp tục.
Sanjiv Jivan

6

Cộng đồng Apache

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

+1, IMHO, đây là cái sạch nhất khi bạn làm việc với mã cũ. Chỉ cần nhập thêm một nhập tĩnh addDays(..)và nó thậm chí còn ngắn hơn.
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

Chúng ta có thể di chuyển logic sang các phương thức khác nhau kẻ thù Java 7, Java 8 và 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());
}

Sau đó, chúng ta có thể gọi các phương thức này như:

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

Đầu ra sẽ là:

[Mon Dec 20 00:00:00 IST 2010, Tue 21/12 00:00:00 IST 2010, Wed 22/12 00:00:00 IST 2010, Thu Dec 23 00:00:00 IST 2010, Fri 24/12: 00/12 00:00 IST 2010, Thứ bảy ngày 25 tháng 12 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
Sự khủng khiếp DateCalendarcác lớp học đã được thay thế bởi các lớp java.time năm trước. Cụ thể, được thay thế bởi InstantZonedDateDate.
Basil Bourque

1
Tôi thích cách Java 8 và 9. Đối với Java 6 và 7, tôi khuyên bạn nên sử dụng thư viện ThreeTen Backport và tương tự như trong Java 8. Bạn chứng minh độc đáo cách này rõ ràng hơn và thân thiện với lập trình viên hơn.
Ole VV

2

Đây là mã Java 8. Tôi nghĩ rằng mã này sẽ giải quyết vấn đề của bạn. Mã hóa hạnh phúc

    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

Đây là cách tiếp cận tốt nhất và dễ dàng mà bạn có thể theo dõi.
jatin Gidel

1

Tại sao không sử dụng epoch và lặp qua dễ dàng.

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

Bạn có thể viết một lớp giống như nó (thực hiện giao diện iterator) và lặp lại trên nó.

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

và sử dụng nó như:

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

}

1

Bạn có thể thử điều này:

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

0

Điều này sẽ giúp bạn bắt đầu 30 ngày trở lại và lặp lại cho đến ngày hôm nay. bạn có thể dễ dàng thay đổi phạm vi ngày và hướng.

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());
        }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.