cálculo del último día del mes


144

Tengo problemas con el cálculo de cuándo el próximo último día del mes es para una notificación que está programada para ser enviada.

Aquí está mi código:

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

Esta es la línea que causa problemas que creo:

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

¿Cómo puedo usar el Calendario para configurar correctamente el último día del próximo mes para la notificación?


1
Ajústelo al primer día del mes siguiente y luego retroceda un día.
Bill

Un SSCCE facilitaría responder esta pregunta. ¿Qué problema estás viendo realmente?
ADN

Respuestas:


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

Esto devuelve el máximo real para el mes actual. Por ejemplo, ahora es febrero del año bisiesto, por lo que devuelve 29 como int.


gracias, necesito obtener el máximo para el próximo mes, sin embargo, también tiene que funcionar para que pueda ser el primer día del mes, ya que esa parte funciona ahora. gracias de nuevo por su tiempo y esfuerzo
OakvilleWork

44
No es un problema ActualMaximumpara cada fecha. Simplemente pase la instancia del calendario a la fecha requerida antes de llamar getActualMaximum. La primera fecha se puede obtener porgetActualMinimum()
AlexR

ok muchas gracias Alex, así que si deseo pasar la instancia a un mes por delante y averiguar el getActualMaximum para ese mes, ¿cómo lo haría? aplausos
OakvilleWork

¿sería este Alex? nextNotifTime.roll (Calendar.MONTH, verdadero); nextNotifTime.getActualMaximum (Calendar.DAY_OF_MONTH);
OakvilleWork

También configuré la fecha y hora lista después de esto: nextNotification.setReadyDateTime(nextNotifTime.getTime()); por lo tanto, ¿no debería hacer esto en su lugar nextNotifTime.roll(Calendar.MONTH, true); nextNotifTime.getActualMaximum(Calendar.DAY_OF_MONTH); nextNotifTime.setTime(Calendar.DAY_OF_MONTH); :?
OakvilleWork

61

java.time.temporal.TemporalAdjusters.lastDayOfMonth ()

Usando la java.timebiblioteca integrada en Java 8, puede usar la TemporalAdjusterinterfaz. Nos encontramos con una aplicación lista para su uso en la TemporalAdjustersclase de utilidad: 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 necesita agregar información de tiempo, puede usar cualquier disponible LocalDatepara la LocalDateTimeconversión como

lastDay.atStartOfDay(); //2015-11-30T00:00

Buena respuesta. Pero esa última parte es débil, lo que sugiere el uso de LocalDateTime. Esa clase carece de cualquier concepto de zona horaria o desplazamiento desde UTC. Por lo tanto, no puede determinar cuándo comienza un día en particular en un lugar en particular. Esa clase solo funciona para días genéricos de 24 horas, no para días del mundo real. Para los días reales, especifique una zona horaria: ZonedDateTime zdt = now.atStartOfDay( ZoneId.of( "Asia/Tokyo" ) ) ;. Algunos días en algunos lugares pueden comenzar a una hora diferente, como 01:00, debido a anomalías como el horario de verano (DST).
Basil Bourque

35

Y para obtener el último día como objeto Fecha:

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

Date lastDayOfMonth = cal.getTime();

22

Puede configurar el calendario al primero del próximo mes y luego restar un día.

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

Después de ejecutar este código, nextNotifTime se establecerá en el último día del mes actual. Tenga en cuenta que si hoy es el último día del mes, el efecto neto de este código es que el objeto Calendario permanece sin cambios.


17

Lo siguiente siempre dará resultados adecuados:

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

¿Por qué es necesario? ¿Podría decirme :)
Frank Fang

1
Sí, las pruebas fallaron por este motivo exacto. El problema es que, a menos que se establezca DAY_OF_MONTH, el valor predeterminado será el actual.
ppearcy

7

Usar la última java.timebiblioteca aquí es la mejor solución:

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

Alternativamente, puedes hacer:

LocalDate endOfMonth = date.withDayOfMonth(date.lengthOfMonth());


2

Mira el getActualMaximum(int field)método del objeto Calendario.

Si configura su objeto Calendario para estar en el mes para el que está buscando la última fecha, getActualMaximum(Calendar.DAY_OF_MONTH)le dará el último día.


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

Implementación de extensión de fecha Kotlin usando 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
}

Puede llamar a la toEndOfMonthfunción en cada objeto Fecha comoDate().toEndOfMonth()


44
Estas clases terribles fueron suplantadas hace años por las modernas clases java.time con la adopción de JSR 310. Sugerir estas clases heredadas en 2019 es un mal consejo.
Basil Bourque

No es un mal consejo. El java.time moderno está disponible para Android solo para API 26+. Todavía dependemos de java.util. * Cuando se admiten dispositivos antiguos (no tan).
Rafael Chagas
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.