последний день месяца расчет

149

У меня возникают проблемы с вычислением того, когда в следующий последний день месяца будет отправлено уведомление, которое планируется отправить.

Вот мой код:

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

Я считаю, что эта строка вызывает проблемы:

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

Как я могу использовать Календарь, чтобы правильно установить последний день следующего месяца для уведомления?

OakvilleWork
источник
1
Установите первый день следующего месяца, а затем выполните откат на один день.
Bill
SSCCE будет легче ответить на этот вопрос. Какую проблему вы на самом деле видите?
DNA

Ответы:

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

Это возвращает фактический максимум за текущий месяц. Например, сейчас февраль високосного года, поэтому он возвращает 29 как int.

AlexR
источник
спасибо, мне нужно получить максимум на следующий месяц, но он еще должен работать, что это может быть и первый день месяца, так как эта часть работает сейчас. еще раз спасибо за ваше время и усилия
OakvilleWork
4
Получить ActualMaximumна каждое свидание - не проблема . Просто перед звонком сверните экземпляр календаря на нужную дату getActualMaximum. Первое свидание может быть полученоgetActualMinimum()
AlexR
хорошо, большое спасибо, Алекс, так что, если я хочу откатить экземпляр до месяца вперед и узнать getActualMaximum за этот месяц, как бы я это сделал? ура
OakvilleWork
это будет Алекс? nextNotifTime.roll (Calendar.MONTH, истина); nextNotifTime.getActualMaximum (Calendar.DAY_OF_MONTH);
OakvilleWork
Также я установил готовое время после даты этого: nextNotification.setReadyDateTime(nextNotifTime.getTime()); поэтому я не должен делать это вместо: nextNotifTime.roll(Calendar.MONTH, true); nextNotifTime.getActualMaximum(Calendar.DAY_OF_MONTH); nextNotifTime.setTime(Calendar.DAY_OF_MONTH); ?
OakvilleWork
63

java.time.temporal.TemporalAdjusters.lastDayOfMonth ()

Используя java.timeвстроенную в Java 8 библиотеку, вы можете использовать TemporalAdjusterинтерфейс. Мы считаем , реализация готова к использованию в TemporalAdjustersклассе полезности: 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

Если вам нужно добавить информацию о времени, вы можете использовать любую доступную LocalDateдля LocalDateTimeпреобразования, например

lastDay.atStartOfDay(); //2015-11-30T00:00
Przemek
источник
Хороший ответ. Но эта последняя часть слабая и предполагает использование LocalDateTime. В этом классе отсутствует понятие часового пояса или смещения от UTC. Таким образом, он не может определить, когда на самом деле начинается конкретный день в конкретном месте. Этот класс работает только для обычных 24-часовых дней, а не для реальных дней. Для настоящих дней, указать часовой пояс: ZonedDateTime zdt = now.atStartOfDay( ZoneId.of( "Asia/Tokyo" ) ) ;. Некоторые дни в некоторых местах могут начинаться в другое время, например, 01:00, из-за аномалий, таких как переход на летнее время (DST).
Basil
35

И чтобы получить последний день как объект Date:

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

Date lastDayOfMonth = cal.getTime();
еще
источник
22

Вы можете установить календарь на первое число следующего месяца, а затем вычесть день.

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

После запуска этого кода nextNotifTime будет установлен на последний день текущего месяца. Имейте в виду, что если сегодня последний день месяца, чистый эффект этого кода заключается в том, что объект Calendar остается неизменным.

Майк Палуба
источник
18

Следующие действия всегда будут давать правильные результаты:

    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();
Сафван Котавала
источник
Зачем это нужно? Не могли бы вы мне сказать :)
Фрэнк Фанг
1
Да, только что тесты провалились именно по указанной выше причине. Проблема в том, что если не задано значение DAY_OF_MONTH, по умолчанию будет использоваться текущий.
ppearcy
7

java.timeЛучшее решение - использовать последнюю версию библиотеки:

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

В качестве альтернативы вы можете:

LocalDate endOfMonth = date.withDayOfMonth(date.lengthOfMonth());
сатнам
источник
3

Посмотрите на getActualMaximum(int field)метод объекта Calendar.

Если вы установите объект Calendar в том месяце, для которого вы ищете последнюю дату, тогда getActualMaximum(Calendar.DAY_OF_MONTH)вы получите последний день.

Бруно
источник
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

Реализация расширения даты Kotlin с использованием 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
}

Вы можете вызвать toEndOfMonthфункцию для каждого объекта Date, напримерDate().toEndOfMonth()

гохан
источник
4
Эти ужасные классы были вытеснены много лет назад современными классами java.time с принятием JSR 310. Предлагать эти устаревшие классы в 2019 году - плохой совет.
Basil
Это неплохой совет. Современный java.time доступен для Android только для API 26+. Мы по-прежнему зависим от java.util. * При поддержке (не очень) старых устройств.
Рафаэль Шагас,