Java 8 LocalDate-Comment obtenir toutes les dates entre deux dates?


Existe-t-il une utilité pour obtenir toutes les dates entre deux dates dans la nouvelle API java.time?

Disons que j'ai cette partie du code:

@Test
public void testGenerateChartCalendarData() {
    LocalDate startDate = LocalDate.now();

    LocalDate endDate = startDate.plusMonths(1);
    endDate = endDate.withDayOfMonth(endDate.lengthOfMonth());
}

Maintenant j'ai besoin de toutes les dates entre startDate et endDate.

Je pensais obtenir le daysBetween des deux dates et parcourir:

long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);

for(int i = 0; i <= daysBetween; i++){
    startDate.plusDays(i); //...do the stuff with the new date...
}

Est-il un meilleur moyen d'obtenir les dates?

Author: Patrick, 2016-07-06

9 answers

En supposant que vous souhaitiez principalement itérer sur la plage de dates, il serait logique de créer une classe DateRange itérable. Cela vous permettrait d'écrire:

for (LocalDate d : DateRange.between(startDate, endDate)) ...

Quelque Chose comme:

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

Il serait logique d'ajouter des méthodes equals & hashcode, des getters, peut-être avoir une usine statique + un constructeur privé pour correspondre au style de codage de l'API Java time, etc.

 46
Author: assylias, 2016-07-06 11:25:31

Abord, vous pouvez utiliser un TemporalAdjuster pour obtenir le dernier jour du mois. Ensuite, l'API Stream offre Stream::iterate quel est le bon outil pour votre problème.

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);
 50
Author: Flown, 2016-07-06 09:35:15

Java 9

Dans Java 9, la classe LocalDatea été améliorée avec le LocalDate.datesUntil (LocalDate endExclusive) méthode, qui renvoie toutes les dates dans une plage de dates en tant que Stream<LocalDate>.

List<LocalDate> dates = startDate.datesUntil(endDate).collect(Collectors.toList());
 12
Author: Durgpal Singh, 2018-09-20 04:54:52

Vous pouvez utiliser le .isAfter et .plusDays pour le faire sur une boucle. Je ne dirais pas mieuxcar je n'ai pas fait beaucoup de recherches sur le sujet, mais je peux dire avec confiance qu'il utilise l'API Java 8 et est une alternative légère.

LocalDate startDate = LocalDate.now();
LocalDate endDate = startDate.plusMonths(1);
while (!startDate.isAfter(endDate)) {
 System.out.println(startDate);
 startDate = startDate.plusDays(1);
}

Sortie

2016-07-05
2016-07-06
...
2016-08-04
2016-08-05

Exemple Ici

 7
Author: N.J.Dawson, 2016-07-06 09:34:03

Vous pouvez créer un stream d'objets LocalDate. J'ai eu ce problème aussi et j'ai publié ma solution en tant que java-timestream sur github.

En utilisant votre exemple...

LocalDateStream
    .from(LocalDate.now())
    .to(1, ChronoUnit.MONTHS)
    .stream()
    .collect(Collectors.toList());

C'est plus ou moins équivalent aux autres solutions proposées ici, mais cela prend en charge tous les calculs de date et de savoir quand s'arrêter. Vous pouvez fournir des dates de fin spécifiques ou relatives, et lui dire combien de temps pour ignorer chaque itération (la valeur par défaut ci-dessus est un jour).

 6
Author: Todd, 2016-07-06 14:20:33

La bibliothèqueThreeTen-Extra a une classe LocalDateRange qui peut faire exactement ce que vous demandez:

LocalDateRange.ofClosed(startDate, endDate).stream()
        .forEach(/* ...do the stuff with the new date... */);
 2
Author: M. Justin, 2018-09-19 23:40:40

Dans ma bibliothèque de temps Time4J, j'ai écrit un spliterator optimisé pour construire un flux de dates de calendrier avec de bonnes caractéristiques de parallélisation. Adapté à votre cas d'utilisation:

LocalDate start = ...;
LocalDate end = ...;

Stream<LocalDate> stream = 
  DateInterval.between(start, end) // closed interval, else use .withOpenEnd()
    .streamDaily()
    .map(PlainDate::toTemporalAccessor);

Cette approche courte peut être un point de départ intéressant si vous êtes également intéressé par des fonctionnalités connexes telles que les intervalles d'horloge par date de calendrier (flux partitionnés) ou d'autres fonctionnalités d'intervalle et que vous souhaitez éviter le code manuscrit maladroit, voir aussi l'API de DateInterval.

 1
Author: Meno Hochschild, 2016-11-19 21:41:23

Tl; dr

Développer la bonne Réponse de Singh, en utilisant un flux de datesUntil en Java 9 et versions ultérieures.

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 flux

À partir de Java 9, vous pouvez demander un flux de dates. Appel LocalDate::datesUntil.

Commencez par déterminer la date d'aujourd'hui. Cela nécessite un fuseau horaire. Pour un moment donné, la date varie dans le monde entier par zone.

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
LocalDate today = LocalDate.now( z ) ;

Déterminez votre date de fin.

LocalDate stop = today.plusMonths( 1 ) ;

Demandez un flux de dates du début à la fin.

Stream< LocalDate > stream = today.datesUntil( today.plusMonths( 1 ) );

Tirez les dates de ce flux, en les collectant dans un List.

List< LocalDate > datesForMonthFromToday = stream.collect( Collectors.toList() );

Imprimez notre liste de dates, générant du texte au format standard ISO 8601 .

System.out.println( datesForMonthFromToday );

À propos de java.temps

Le java.temps framework est intégré à Java 8 et versions ultérieures. Ces classes permettent d'éviter la pénible vieux héritage date-heure classes telles que java.util.Date, Calendar, & SimpleDateFormat.

Le Joda-Temps projet, maintenant en mode de maintenance, conseille la migration vers le java.temps classes.

Pour en savoir plus, voir le Tutoriel Oracle. Et rechercher Stack Overflow pour de nombreux exemples et explications. La spécification est JSR 310.

, Vous pouvez échanger java.temps objets directement avec votre base de données. Utilisez un pilote JDBC compatible avec JDBC 4.2 ou version ultérieure. Pas besoin de chaînes, pas besoin de classes java.sql.*.

Où obtenir le java.les classes de temps?

Le Trois-Extra le projet étend java.temps avec des cours supplémentaires. Ce projet est un terrain d'essai pour d'éventuels ajouts futurs à java.temps. Vous pouvez trouver quelques classes utiles ici comme Interval, YearWeek, YearQuarter, et plus.

 1
Author: Basil Bourque, 2018-09-20 03:37:14

Vous pouvez utiliser le Range fonctionnalité dans Google Goyave bibliothèque. Après avoir défini leDiscreteDomain sur LocalDate instances, vous pouvez obtenir unContiguousSet de toutes les dates de la plage.

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);
 0
Author: M. Justin, 2018-09-20 04:00:09