Java에서 날짜 범위를 반복하는 방법은 무엇입니까?


144

내 스크립트에서 시작 날짜와 종료 날짜가 주어지면 날짜 범위를 통해 일련의 작업을 수행해야합니다.
Java를 사용하여이를 달성하기위한 지침을 제공해주십시오.

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

}

위의 코드는 단순히 불가능하다는 것을 알고 있지만 달성하고자하는 것을 보여주기 위해 수행합니다.


답변:


198

글쎄, 이 문제에 대해 Java 8의 time-API를 사용하여 이와 같은 작업을 수행 할 수 있습니다 java.time.LocalDate(또는 Java 7 이상에 해당하는 Joda Time 클래스)

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

나는 것 철저하게 사용하는 것이 좋습니다 java.time내장 이상 (또는 Joda 시간) Date/ Calendar수업.


2
Joda Time에 대한 요점을 넓히기 위해 : 이것을 직접 구현하는 것은 여름철의 변경과 여름철의 변화에 ​​대한 코너 케이스로 인해 생각하는 것보다 어렵습니다.
Raedwald

Joda의 경우 +1, 언젠가 표준 API에 도달하기를 바랍니다.
gyorgyabraham

4
@ gyabraham : JSR-310은 Java 8에서 꽤 좋은 모습을 보이고 있습니다.
Jon Skeet

4
이 동일한 코드가 Joda 대신 Java 8의 java.time.LocalDate를 사용하여 작동하는지 확인할 수 있습니다.
Molten Ice

3
Joda-Time 프로젝트는 현재 유지 보수 모드에 있으며 java.time 클래스로의 마이그레이션을 권장합니다. 주석에서 언급 했듯이이 Answer의 코드는 java.time에서 그대로 작동하며 import명령문을 변경하십시오 .
바질 부르 케

146

그러나 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 9datesUntil () 메소드를 추가했습니다 .

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

1
배수 값을 넣을 수 있습니까? 단 월요일 또는 목요일 또는 둘 다 : 예
대인 수수

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
로직에 "continue"문이 포함 된 경우 BalusC의 for 루프 버전이 continue 문으로 작동하는 경우에는 작동하지 않습니다.
Sanjiv Jivan

6

아파치 커먼즈

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

+1, IMHO, 이것은 오래된 코드로 작업 할 때 가장 깨끗합니다. 추가 정적 가져 오기를 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의 년 전 클래스. 구체적으로 Instantand 로 대체되었습니다 ZonedDateDate.
Basil Bourque

1
Java 8 및 9 방식이 마음에 듭니다. Java 6 및 7의 경우 ThreeTen Backport 라이브러리를 사용 하고 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

1

에포크 (epoch)를 사용하고 쉽게 루프 스루하지 마십시오.

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

iterator 인터페이스 구현과 같은 클래스를 작성하고 반복 할 수 있습니다.

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.