diff --git a/jdk/src/java.base/share/classes/java/time/LocalDate.java b/jdk/src/java.base/share/classes/java/time/LocalDate.java index 3d8c034fa91..940f21f0f1e 100644 --- a/jdk/src/java.base/share/classes/java/time/LocalDate.java +++ b/jdk/src/java.base/share/classes/java/time/LocalDate.java @@ -100,6 +100,8 @@ import java.time.temporal.ValueRange; import java.time.zone.ZoneOffsetTransition; import java.time.zone.ZoneRules; import java.util.Objects; +import java.util.stream.LongStream; +import java.util.stream.Stream; /** * A date without a time-zone in the ISO-8601 calendar system, @@ -1715,6 +1717,89 @@ public final class LocalDate return Period.of(Math.toIntExact(years), months, days); } + /** + * Returns a sequential ordered stream of dates. The returned stream starts from this date + * (inclusive) and goes to {@code endExclusive} (exclusive) by an incremental step of 1 day. + *
+ * This method is equivalent to {@code datesUntil(endExclusive, Period.ofDays(1))}.
+ *
+ * @param endExclusive the end date, exclusive, not null
+ * @return a sequential {@code Stream} for the range of {@code LocalDate} values
+ * @throws IllegalArgumentException if end date is before this date
+ * @since 9
+ */
+ public Stream
+ * The n-th date which appears in the stream is equal to {@code this.plus(step.multipliedBy(n))}
+ * (but the result of step multiplication never overflows). For example, if this date is
+ * {@code 2015-01-31}, the end date is {@code 2015-05-01} and the step is 1 month, then the
+ * stream contains {@code 2015-01-31}, {@code 2015-02-28}, {@code 2015-03-31}, and
+ * {@code 2015-04-30}.
+ *
+ * @param endExclusive the end date, exclusive, not null
+ * @param step the non-zero, non-negative {@code Period} which represents the step.
+ * @return a sequential {@code Stream} for the range of {@code LocalDate} values
+ * @throws IllegalArgumentException if step is zero, or {@code step.getDays()} and
+ * {@code step.toTotalMonths()} have opposite sign, or end date is before this date
+ * and step is positive, or end date is after this date and step is negative
+ * @since 9
+ */
+ public Stream
diff --git a/jdk/test/java/time/tck/java/time/TCKLocalDate.java b/jdk/test/java/time/tck/java/time/TCKLocalDate.java
index 96290401c97..2b5832465c9 100644
--- a/jdk/test/java/time/tck/java/time/TCKLocalDate.java
+++ b/jdk/test/java/time/tck/java/time/TCKLocalDate.java
@@ -119,6 +119,8 @@ import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
@@ -2385,4 +2387,204 @@ public class TCKLocalDate extends AbstractDateTimeTest {
assertSame(isoEra,IsoEra.CE);
assertSame(LocalDate.MIN.getEra(),IsoEra.BCE);
}
+
+ //-----------------------------------------------------------------
+ // datesUntil()
+ // ----------------------------------------------------------------
+ @Test
+ public void test_datesUntil() {
+ assertEquals(
+ date(2015, 9, 29).datesUntil(date(2015, 10, 3)).collect(
+ Collectors.toList()), Arrays.asList(date(2015, 9, 29),
+ date(2015, 9, 30), date(2015, 10, 1), date(2015, 10, 2)));
+ assertEquals(date(2015, 9, 29).datesUntil(date(2015, 10, 3), Period.ofDays(2))
+ .collect(Collectors.toList()), Arrays.asList(date(2015, 9, 29),
+ date(2015, 10, 1)));
+ assertEquals(date(2015, 1, 31).datesUntil(date(2015, 6, 1), Period.ofMonths(1))
+ .collect(Collectors.toList()), Arrays.asList(date(2015, 1, 31),
+ date(2015, 2, 28), date(2015, 3, 31), date(2015, 4, 30),
+ date(2015, 5, 31)));
+ }
+
+ @Test(expectedExceptions=NullPointerException.class)
+ public void test_datesUntil_nullEnd() {
+ LocalDate date = date(2015, 1, 31);
+ date.datesUntil(null);
+ }
+
+ @Test(expectedExceptions=NullPointerException.class)
+ public void test_datesUntil_nullEndStep() {
+ LocalDate date = date(2015, 1, 31);
+ date.datesUntil(null, Period.ofDays(1));
+ }
+
+ @Test(expectedExceptions=NullPointerException.class)
+ public void test_datesUntil_nullStep() {
+ LocalDate date = date(2015, 1, 31);
+ date.datesUntil(date, null);
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void test_datesUntil_endBeforeStart() {
+ date(2015, 1, 31).datesUntil(date(2015, 1, 30));
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void test_datesUntil_endBeforeStartPositiveStep() {
+ date(2015, 1, 31).datesUntil(date(2015, 1, 30), Period.of(1, 0, 0));
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void test_datesUntil_endAfterStartNegativeStep() {
+ date(2015, 1, 30).datesUntil(date(2015, 1, 31), Period.of(0, -1, -1));
+ }
+
+ @Test(expectedExceptions=IllegalArgumentException.class)
+ public void test_datesUntil_zeroStep() {
+ LocalDate date = date(2015, 1, 31);
+ date.datesUntil(date, Period.ZERO);
+ }
+
+ @Test(expectedExceptions=IllegalArgumentException.class)
+ public void test_datesUntil_oppositeSign() {
+ LocalDate date = date(2015, 1, 31);
+ date.datesUntil(date, Period.of(1, 0, -1));
+ }
+
+ @Test(expectedExceptions=IllegalArgumentException.class)
+ public void test_datesUntil_oppositeSign2() {
+ LocalDate date = date(2015, 1, 31);
+ date.datesUntil(date, Period.of(0, -1, 1));
+ }
+
+ @DataProvider(name="datesUntil")
+ public Object[][] provider_datesUntil() {
+ return new Object[][] {
+ {MIN_DATE, MIN_DATE},
+ {MIN_DATE, MAX_DATE},
+ {MAX_DATE, MAX_DATE},
+ {date(2015,10,1), date(2015,10,2)},
+ {date(2015,10,1), date(2015,11,1)},
+ {date(2015,10,31), date(2015,11,1)},
+ {date(2015,10,1), MAX_DATE},
+ {MIN_DATE, date(2015,10,1)}
+ };
+ }
+
+ @Test(dataProvider = "datesUntil")
+ public void test_datesUntil_count(LocalDate start, LocalDate end) {
+ assertEquals(start.datesUntil(end).count(), start.until(end, ChronoUnit.DAYS));
+ assertEquals(start.datesUntil(end, Period.ofDays(1)).count(),
+ start.until(end, ChronoUnit.DAYS));
+ }
+
+ @DataProvider(name="datesUntilSteps")
+ public Object[][] provider_datesUntil_steps() {
+ List