cálculo do último dia do mês


144

Estou tendo problemas com o cálculo de quando o próximo último dia do mês é para uma notificação que está programada para ser enviada.

Aqui está o meu código:

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

Esta é a linha que causa problemas que acredito:

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

Como posso usar o calendário para definir corretamente o último dia do próximo mês para a notificação?


1
Defina-o para o primeiro dia do próximo mês e depois reverta um dia.
Bill

Um SSCCE facilitaria a resposta a essa pergunta. Que problema você está realmente vendo?
DNA

Respostas:


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

Isso retorna o máximo real para o mês atual. Por exemplo, agora é fevereiro do ano bissexto, retornando 29 como int.


obrigado, eu preciso obter o máximo para o próximo mês, no entanto, ainda é necessário que ele possa ser o primeiro dia do mês, pois essa parte funciona agora. Obrigado novamente por seu tempo e esforço
OakvilleWork

4
Não é um problema para obter ActualMaximumpara cada data. Basta rolar a instância do calendário para a data necessária antes de ligar getActualMaximum. A primeira data pode ser obtida porgetActualMinimum()
AlexR

ok, muito obrigado Alex, por isso, se eu desejar rolar a instância para um mês à frente e descobrir o getActualMaximum desse mês, como eu faria isso? vivas
OakvilleWork

seria este Alex? nextNotifTime.roll (Calendar.MONTH, true); nextNotifTime.getActualMaximum (Calendar.DAY_OF_MONTH);
precisa

Também defino a hora da data pronta após isso: nextNotification.setReadyDateTime(nextNotifTime.getTime()); portanto, não devo fazer isso nextNotifTime.roll(Calendar.MONTH, true); nextNotifTime.getActualMaximum(Calendar.DAY_OF_MONTH); nextNotifTime.setTime(Calendar.DAY_OF_MONTH); :?
precisa

61

java.time.temporal.TemporalAdjusters.lastDayOfMonth ()

Usando a java.timebiblioteca integrada no Java 8, você pode usar a TemporalAdjusterinterface. Encontramos uma implementação pronta para uso na TemporalAdjustersclasse de utilitário: 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

Se você precisar adicionar informações de horário, poderá usar qualquer disponível LocalDatepara LocalDateTimeconversão, como

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

Boa resposta. Mas essa última parte é fraca, sugerindo o uso de LocalDateTime. Essa classe não possui nenhum conceito de fuso horário ou deslocamento do UTC. Portanto, não é possível determinar quando um determinado dia em um determinado local realmente começa. Essa classe funciona apenas para dias genéricos simples de 24 horas, não para dias do mundo real. Para os dias de reais, especificar um fuso horário: ZonedDateTime zdt = now.atStartOfDay( ZoneId.of( "Asia/Tokyo" ) ) ;. Alguns dias em alguns locais podem começar em um horário diferente, como 01:00, devido a anomalias como horário de verão (DST).
Basil Bourque

35

E para obter o último dia como objeto Data:

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

Date lastDayOfMonth = cal.getTime();

22

Você pode definir o calendário para o primeiro mês que vem e subtrair um dia.

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

Depois de executar esse código, nextNotifTime será definido como o último dia do mês atual. Lembre-se de que hoje é o último dia do mês, o efeito líquido desse código é que o objeto Calendário permaneça inalterado.


17

A seguir, sempre haverá resultados adequados:

    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 que é necessário? Poderia dizer-me :)
Frank fang

1
Sim, apenas os testes falharam por esse exato motivo acima. O problema é que, a menos que DAY_OF_MONTH esteja definido, o padrão será atual.
ppearcy

7

Usar a java.timebiblioteca mais recente aqui é a melhor solução:

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

Como alternativa, você pode fazer:

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


2

Veja o getActualMaximum(int field)método do objeto Calendário.

Se você definir o objeto Calendário como o mês para o qual está buscando a última data, getActualMaximum(Calendar.DAY_OF_MONTH)o último dia será exibido.


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

Implementação de extensão de data 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
}

Você pode chamar a toEndOfMonthfunção em cada objeto Date, comoDate().toEndOfMonth()


4
Essas classes terríveis foram substituídas há anos pelas modernas classes java.time com a adoção do JSR 310. Sugerir essas classes herdadas em 2019 é um péssimo conselho.
Basil Bourque

Não é um mau conselho. O java.time moderno está disponível para Android apenas para API 26+. Ainda dependemos do java.util. * Para oferecer suporte a dispositivos antigos (não muito).
Rafael Chagas
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.