restar - Java 8 LocalDate: ¿cómo obtengo todas las fechas entre dos fechas?
localdate java ejemplo (9)
tl; dr
Ampliando la buena
respuesta de Singh
, utilizando una secuencia de
datesUntil
en Java 9 y posterior.
today // Determine your beginning `LocalDate` object.
.datesUntil( // Generate stream of `LocalDate` objects.
today.plusMonths( 1 ) // Calculate your ending date, and ask for a stream of dates till then.
) // Returns the stream.
.collect( Collectors.toList() ) // Collect your resulting dates in a `List`.
.toString() // Generate text representing your found dates.
[2018-09-20, 2018-09-21, 2018-09-22, 2018-09-23, 2018-09-24, 2018-09-25, 2018-09-26, 2018-09-27, 2018 -09-28, 2018-09-29, 2018-09-30, 2018-10-01, 2018-10-02, 2018-10-03, 2018-10-04, 2018-10-05, 2018-10 -06, 2018-10-07, 2018-10-08, 2018-10-09, 2018-10-10, 2018-10-11, 2018-10-12, 2018-10-13, 2018-10-14 , 2018-10-15, 2018-10-16, 2018-10-17, 2018-10-18, 2018-10-19]
LocalDate::datesUntil
stream
A partir de Java 9, puede solicitar una secuencia de fechas. Llame a datesUntil .
Comience por determinar la fecha de hoy. Eso requiere una zona horaria. Para cualquier momento, la fecha varía en todo el mundo por zona.
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
LocalDate today = LocalDate.now( z ) ;
Determina tu fecha de finalización.
LocalDate stop = today.plusMonths( 1 ) ;
Solicite una secuencia de fechas de principio a fin.
Stream< LocalDate > stream = today.datesUntil( today.plusMonths( 1 ) );
Extraiga las fechas de esa secuencia, reuniéndolas en una
List
.
List< LocalDate > datesForMonthFromToday = stream.collect( Collectors.toList() );
Imprima nuestra lista de fechas, generando texto en formato estándar ISO 8601 .
System.out.println( datesForMonthFromToday );
Sobre java.time
El marco
java.time
está integrado en Java 8 y
java.time
posteriores.
Estas clases suplantan a las antiguas y problemáticas clases de fecha y hora
legacy
, como
java.util.Date
,
Calendar
y
SimpleDateFormat
.
El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .
Para obtener más información, consulte el Tutorial de Oracle . Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310 .
Puede intercambiar objetos
java.time
directamente con su base de datos.
Utilice un
controlador JDBC
compatible con
JDBC 4.2
o posterior.
No necesita cadenas, no necesita clases
java.sql.*
.
¿Dónde obtener las clases java.time?
-
Java SE 8
,
Java SE 9
,
Java SE 10
,
Java SE 11
y versiones posteriores: parte de la API Java estándar con una implementación integrada.
- Java 9 agrega algunas características menores y correcciones.
-
Java SE 6
y
Java SE 7
- La mayor parte de la funcionalidad java.time se transfiere a Java 6 y 7 en ThreeTen-Backport .
-
Android
- Versiones posteriores de las implementaciones de paquetes de Android de las clases java.time .
- Para Android anterior (<26), el proyecto ThreeTen-Backport adapta ThreeTen-Backport (mencionado anteriormente). Vea Cómo usar ThreeTenABP ...
El proyecto
ThreeTen-Extra
extiende java.time con clases adicionales.
Este proyecto es un campo de pruebas para posibles adiciones futuras a java.time.
Puede encontrar algunas clases útiles aquí, como
Interval
,
YearWeek
,
YearQuarter
y
more
.
¿Existe una usabilidad para obtener
todas las fechas entre dos fechas
en la nueva API
java.time
?
Digamos que tengo esta parte del código:
@Test
public void testGenerateChartCalendarData() {
LocalDate startDate = LocalDate.now();
LocalDate endDate = startDate.plusMonths(1);
endDate = endDate.withDayOfMonth(endDate.lengthOfMonth());
}
Ahora necesito todas las fechas entre
startDate
y
endDate
.
Estaba pensando en obtener los
daysBetween
entre las dos fechas e iterar sobre:
long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);
for(int i = 0; i <= daysBetween; i++){
startDate.plusDays(i); //...do the stuff with the new date...
}
¿Hay una mejor manera de obtener las fechas?
En mi biblioteca de tiempo Time4J , he escrito un spliterator optimizado para construir una secuencia de fechas de calendario con buenas características de paralelización. Adaptado a su caso de uso:
LocalDate start = ...;
LocalDate end = ...;
Stream<LocalDate> stream =
DateInterval.between(start, end) // closed interval, else use .withOpenEnd()
.streamDaily()
.map(PlainDate::toTemporalAccessor);
Este breve enfoque puede ser un punto de partida interesante si también está interesado en características relacionadas como intervalos de reloj por fecha de calendario (secuencias particionadas) u otras características de intervalo y desea evitar el código incómodo escrito a mano, consulte también la API de DateInterval .
La biblioteca ThreeTen-Extra tiene una clase LocalDateRange que puede hacer exactamente lo que está solicitando:
LocalDateRange.ofClosed(startDate, endDate).stream()
.forEach(/* ...do the stuff with the new date... */);
Primero puede usar un
TemporalAdjuster
para obtener el último día del mes.
A continuación,
Stream
API ofrece
Stream::iterate
que es la herramienta adecuada para su problema.
LocalDate start = LocalDate.now();
LocalDate end = LocalDate.now().plusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
List<LocalDate> dates = Stream.iterate(start, date -> date.plusDays(1))
.limit(ChronoUnit.DAYS.between(start, end))
.collect(Collectors.toList());
System.out.println(dates.size());
System.out.println(dates);
Puede crear una
stream
de objetos
LocalDate
.
También tuve este problema y publiqué mi solución como
java-timestream en github.
Usando tu ejemplo ...
LocalDateStream
.from(LocalDate.now())
.to(1, ChronoUnit.MONTHS)
.stream()
.collect(Collectors.toList());
Es más o menos equivalente a otras soluciones propuestas aquí, pero se encarga de todas las matemáticas de fechas y saber cuándo parar. Puede proporcionar fechas de finalización específicas o relativas y decirle cuánto tiempo omitir cada iteración (el valor predeterminado anterior es un día).
Puede usar .isAfter y .plusDays para hacer esto en un bucle. No diría mejor, ya que no he investigado mucho sobre el tema, pero puedo decir con confianza que usa la API de Java 8 y es una pequeña alternativa.
LocalDate startDate = LocalDate.now();
LocalDate endDate = startDate.plusMonths(1);
while (!startDate.isAfter(endDate)) {
System.out.println(startDate);
startDate = startDate.plusDays(1);
}
Salida
2016-07-05
2016-07-06
...
2016-08-04
2016-08-05
Puede usar la funcionalidad
Range
en la biblioteca
Guava
de Google.
Después de definir el
DiscreteDomain
sobre
LocalDate
instancias
LocalDate
, puede obtener un
ContiguousSet
de todas las fechas en el rango.
LocalDate d1 = LocalDate.parse("2017-12-25");
LocalDate d2 = LocalDate.parse("2018-01-05");
DiscreteDomain<LocalDate> localDateDomain = new DiscreteDomain<LocalDate>() {
public LocalDate next(LocalDate value) { return value.plusDays(1); }
public LocalDate previous(LocalDate value) { return value.minusDays(1); }
public long distance(LocalDate start, LocalDate end) { return start.until(end, ChronoUnit.DAYS); }
public LocalDate minValue() { return LocalDate.MIN; }
public LocalDate maxValue() { return LocalDate.MAX; }
};
Set<LocalDate> datesInRange = ContiguousSet.create(Range.closed(d1, d2), localDateDomain);
Suponiendo que principalmente desea iterar sobre el rango de fechas, tendría sentido crear una clase
DateRange
que sea iterable.
Eso te permitiría escribir:
for (LocalDate d : DateRange.between(startDate, endDate)) ...
Algo como:
public class DateRange implements Iterable<LocalDate> {
private final LocalDate startDate;
private final LocalDate endDate;
public DateRange(LocalDate startDate, LocalDate endDate) {
//check that range is valid (null, start < end)
this.startDate = startDate;
this.endDate = endDate;
}
@Override
public Iterator<LocalDate> iterator() {
return stream().iterator();
}
public Stream<LocalDate> stream() {
return Stream.iterate(startDate, d -> d.plusDays(1))
.limit(ChronoUnit.DAYS.between(startDate, endDate) + 1);
}
public List<LocalDate> toList() { //could also be built from the stream() method
List<LocalDate> dates = new ArrayList<> ();
for (LocalDate d = startDate; !d.isAfter(endDate); d = d.plusDays(1)) {
dates.add(d);
}
return dates;
}
}
Tendría sentido agregar métodos igual y hashcode, getters, tal vez tener una fábrica estática + constructor privado para que coincida con el estilo de codificación de la API de tiempo de Java, etc.
Java 9
En Java 9, la clase
LocalDate
se mejoró con el
método LocalDate.datesUntil (LocalDate endExclusive)
, que devuelve todas las fechas dentro de un rango de fechas como
Stream<LocalDate>
.
List<LocalDate> dates = startDate.datesUntil(endDate).collect(Collectors.toList());