calcul du dernier jour du mois

144

Je rencontre des problèmes avec le calcul du moment auquel le prochain dernier jour du mois correspond à une notification qui doit être envoyée.

Voici mon code:

RecurrenceFrequency recurrenceFrequency = notification.getRecurrenceFrequency();
Calendar nextNotifTime = Calendar.getInstance();

C'est la ligne qui cause des problèmes, je crois:

nextNotifTime.add(recurrenceFrequency.getRecurrencePeriod(), 
                  recurrenceFrequency.getRecurrenceOffset());

Comment puis-je utiliser le calendrier pour définir correctement le dernier jour du mois suivant pour la notification?

OakvilleTravail
la source
1
Réglez-le sur le premier jour du mois suivant, puis revenez en arrière d'un jour.
Projet de loi du
Un SSCCE permettrait de répondre plus facilement à cette question. Quel problème voyez-vous réellement?
DNA

Réponses:

347
Calendar.getInstance().getActualMaximum(Calendar.DAY_OF_MONTH);

Cela renvoie le maximum réel pour le mois en cours. Par exemple, c'est février de l'année bissextile maintenant, donc il renvoie 29 comme int.

AlexR
la source
merci, j'ai besoin d'obtenir le maximum pour le mois prochain cependant, il faut aussi que cela puisse être le premier jour du mois aussi, car cette partie fonctionne maintenant. merci encore pour votre temps et vos efforts
OakvilleWork
4
Ce n'est pas un problème à obtenir ActualMaximumpour chaque date. Faites simplement rouler l'instance de calendrier à la date requise avant d'appeler getActualMaximum. La première date peut être obtenue pargetActualMinimum()
AlexR
ok merci beaucoup Alex, donc si je souhaite rouler l'instance un mois à l'avance et découvrir le getActualMaximum pour ce mois, comment puis-je faire? cheers
OakvilleWork
serait-ce Alex? nextNotifTime.roll (Calendar.MONTH, true); nextNotifTime.getActualMaximum (Calendar.DAY_OF_MONTH);
OakvilleWork
également régler l'heure de date de disponibilité après: nextNotification.setReadyDateTime(nextNotifTime.getTime()); donc je ne devrais pas le faire à la place: nextNotifTime.roll(Calendar.MONTH, true); nextNotifTime.getActualMaximum(Calendar.DAY_OF_MONTH); nextNotifTime.setTime(Calendar.DAY_OF_MONTH); ?
OakvilleWork
61

java.time.temporal.TemporalAdjusters.lastDayOfMonth ()

En utilisant la java.timebibliothèque intégrée à Java 8, vous pouvez utiliser l' TemporalAdjusterinterface. Nous trouvons une implémentation prête à l' emploi dans la TemporalAdjustersclasse utilitaire: lastDayOfMonth.

import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;

LocalDate now = LocalDate.now(); //2015-11-23
LocalDate lastDay = now.with(TemporalAdjusters.lastDayOfMonth()); //2015-11-30

Si vous avez besoin d'ajouter des informations de temps, vous pouvez utiliser tout disponible LocalDatepour la LocalDateTimeconversion comme

lastDay.atStartOfDay(); //2015-11-30T00:00
Przemek
la source
Bonne réponse. Mais cette dernière partie est faible, suggérant l'utilisation de LocalDateTime. Cette classe n'a aucun concept de fuseau horaire ou de décalage par rapport à UTC. Il ne peut donc pas déterminer à quel moment un jour particulier à un endroit particulier commence réellement. Cette classe ne fonctionne que pour les jours génériques simples de 24 heures, pas les jours du monde réel. Pour les jours réels, spécifiez un fuseau horaire: ZonedDateTime zdt = now.atStartOfDay( ZoneId.of( "Asia/Tokyo" ) ) ;. Certains jours à certains endroits peuvent commencer à une heure différente, telle que 01:00, en raison d'anomalies telles que l'heure d'été (DST).
Basil Bourque
35

Et pour obtenir le dernier jour en tant qu'objet Date:

Calendar cal = Calendar.getInstance();
cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DATE));

Date lastDayOfMonth = cal.getTime();
encore une autre
la source
22

Vous pouvez définir le calendrier sur le premier du mois suivant, puis soustraire un jour.

Calendar nextNotifTime = Calendar.getInstance();
nextNotifTime.add(Calendar.MONTH, 1);
nextNotifTime.set(Calendar.DATE, 1);
nextNotifTime.add(Calendar.DATE, -1);

Après avoir exécuté ce code, nextNotifTime sera défini sur le dernier jour du mois en cours. Gardez à l'esprit que si aujourd'hui est le dernier jour du mois, l'effet net de ce code est que l'objet Calendar reste inchangé.

Mike Deck
la source
17

Ce qui suit donnera toujours des résultats appropriés:

    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.MONTH, ANY_MONTH);
    cal.set(Calendar.YEAR, ANY_YEAR);
    cal.set(Calendar.DAY_OF_MONTH, 1);// This is necessary to get proper results
    cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DATE));
    cal.getTime();
Safvan Kothawala
la source
Pourquoi c'est nécessaire? Pourriez-vous me dire :)
Frank Fang
1
Oui, je viens de faire échouer les tests pour cette raison exacte ci-dessus. Le problème est qu'à moins que DAY_OF_MONTH ne soit défini, il sera défini par défaut sur courant.
ppearcy
7

L'utilisation de la dernière java.timebibliothèque est la meilleure solution:

LocalDate date = LocalDate.now();
LocalDate endOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());

Alternativement, vous pouvez faire:

LocalDate endOfMonth = date.withDayOfMonth(date.lengthOfMonth());
satnam
la source
2

Regardez la getActualMaximum(int field)méthode de l'objet Calendar.

Si vous définissez votre objet Calendrier pour qu'il soit dans le mois pour lequel vous recherchez la dernière date, alors getActualMaximum(Calendar.DAY_OF_MONTH)vous donnera le dernier jour.

Bruno
la source
2
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        Date date = sdf.parse("11/02/2016");

        Calendar calendar = Calendar.getInstance();  
        calendar.setTime(date);  

        System.out.println("First Day Of Month : " + calendar.getActualMinimum(Calendar.DAY_OF_MONTH));  
        System.out.println("Last Day of Month  : " + calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); 
Kishore Kumar
la source
1

Implémentation de l'extension de date Kotlin en utilisant java.util.Calendar

fun Date.toEndOfMonth(): Date {
    return Calendar.getInstance().apply {
        time = this@toEndOfMonth
    }.toEndOfMonth().time
}

fun Calendar.toEndOfMonth(): Calendar {
    set(Calendar.DAY_OF_MONTH, getActualMaximum(Calendar.DAY_OF_MONTH))
    return this
}

Vous pouvez appeler la toEndOfMonthfonction sur chaque objet Date commeDate().toEndOfMonth()

gokhan
la source
4
Ces classes terribles ont été supplantées il y a des années par les classes java.time modernes avec l'adoption de JSR 310. Suggérer ces classes héritées en 2019 est un mauvais conseil.
Basil Bourque
Ce n'est pas un mauvais conseil. Le java.time moderne est disponible pour Android uniquement pour l'API 26+. Nous dépendons toujours de java.util. * Pour prendre en charge (pas si) d'anciens appareils.
Rafael Chagas