підрахунок останнього дня місяця


144

У мене виникають проблеми з підрахунком, коли наступного останнього дня місяця буде повідомлення, яке планується відправити.

Ось мій код:

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

Цей рядок викликає проблеми, які я вважаю:

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

Як я можу використовувати Календар, щоб правильно встановити останній день наступного місяця для сповіщення?


1
Встановіть його на перший день наступного місяця, а потім поверніть на один день назад.
Білл

SSCCE буде легше відповісти на це питання. Яку проблему ви насправді бачите?
ДНК

Відповіді:


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

Це повертає фактичний максимум для поточного місяця. Наприклад, це лютий високосного року, тому він повертається 29 як int.


дякую, мені потрібно отримати максимум на наступний місяць, однак, він також повинен працювати, що це може бути і перший день місяця, як це працює зараз. ще раз дякую за ваш час та зусилля
OakvilleWork

4
Це не проблема отримати ActualMaximumна кожне побачення. Просто рол календар екземпляр до необхідної дати перед викликом getActualMaximum. Перше побачення можна отриматиgetActualMinimum()
AlexR

ок, спасибі, Алекс, так що, якщо я хочу прокатати екземпляр на місяць вперед і дізнатися getActualMaximum за цей місяць, як би я це зробив ?? ура
OakvilleWork

це був би Алекс? nextNotifTime.roll (Календар.MONTH, правда); nextNotifTime.getActualMaximum (Календар.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

61

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

Хороша відповідь. Але ця остання частина є слабкою, що говорить про використання LocalDateTime. У цьому класі відсутня будь-яка концепція часового поясу чи зміщення від UTC. Тому він не може визначити, коли конкретно день у певному місці насправді починається. Цей клас працює лише для звичайних цілодобових днів, а не для реальних днів. Для справжніх днів, вказати часовий пояс: ZonedDateTime zdt = now.atStartOfDay( ZoneId.of( "Asia/Tokyo" ) ) ;. Деякі дні в деяких місцях можуть розпочатися в інший час, наприклад 01:00, через аномалії, такі як літній час (DST).
Василь Бурк

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 буде встановлено в останній день поточного місяця. Майте на увазі, якщо сьогодні останній день місяця, чистий ефект цього коду полягає в тому, що об’єкт Календар залишається незмінним.


17

Наступне завжди дасть належні результати:

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


2

Подивіться на getActualMaximum(int field)метод об’єкта Календар.

Якщо ви встановите, що об’єкт календаря буде місяцем, на який ви шукаєте останню дату, тоді 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 році є поганою порадою.
Василь Бурк

Це не погана порада. Сучасний java.time доступний для Android лише для API 26+. Ми все ще залежить від java.util. *, Коли підтримуємо (не дуже) старі пристрої.
Рафаель Чагас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.