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?


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.


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

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();

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é.


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();

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());


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.


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

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()


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.