ostatni dzień obliczenia miesiąca


144

Mam problemy z obliczeniem, kiedy następny ostatni dzień miesiąca przypada na powiadomienie, które ma zostać wysłane.

Oto mój kod:

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

To jest linia powodująca problemy, które moim zdaniem:

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

Jak mogę użyć Kalendarza, aby poprawnie ustawić ostatni dzień następnego miesiąca dla powiadomienia?


1
Ustaw go na pierwszy dzień następnego miesiąca, a następnie cofnij o jeden dzień.
Bill

SSCCE będzie łatwiej odpowiedzieć na to pytanie. Jaki problem faktycznie widzisz?
DNA

Odpowiedzi:


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

Zwraca rzeczywiste maksimum dla bieżącego miesiąca. Na przykład teraz jest luty roku przestępnego, więc zwraca 29 jako int.


dzięki, muszę uzyskać maksimum na następny miesiąc, ale również musi działać, że może to być również pierwszy dzień miesiąca, ponieważ ta część działa teraz. jeszcze raz dziękuję za poświęcony czas i wysiłek
OakvilleWork

4
Nie ma problemu z umówieniem się ActualMaximumna każdą randkę. Po prostu przenieś instancję kalendarza do wymaganej daty przed zadzwonieniem getActualMaximum. Pierwszą datę można uzyskać przezgetActualMinimum()
AlexR

ok, wielkie dzięki Alex, więc jeśli chcę przesunąć instancję na miesiąc do przodu i dowiedzieć się, jaka jest wartość getActualMaximum w tym miesiącu, jak mam to zrobić? pozdrawiam
OakvilleWork

czy to będzie to Alex? nextNotifTime.roll (Calendar.MONTH, true); nextNotifTime.getActualMaximum (Calendar.DAY_OF_MONTH);
OakvilleWork

także ustawić czas po tej dacie gotowe: nextNotification.setReadyDateTime(nextNotifTime.getTime()); w związku z tym nie powinien to zrobić w zamian: nextNotifTime.roll(Calendar.MONTH, true); nextNotifTime.getActualMaximum(Calendar.DAY_OF_MONTH); nextNotifTime.setTime(Calendar.DAY_OF_MONTH); ?
OakvilleWork

61

java.time.temporal.TemporalAdjusters.lastDayOfMonth ()

Korzystając z java.timebiblioteki wbudowanej w Javę 8, możesz korzystać z TemporalAdjusterinterfejsu. Znaleźć implementacja gotowy do użycia w TemporalAdjustersklasie użytkowej: 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

Jeśli chcesz dodać informacje o czasie, możesz użyć dowolnego dostępnego LocalDatedo LocalDateTimekonwersji, takiego jak

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

Dobra odpowiedź. Ale ta ostatnia część jest słaba, co sugeruje użycie LocalDateTime. W tej klasie brakuje jakiejkolwiek koncepcji strefy czasowej lub przesunięcia względem czasu UTC. Nie może więc określić, kiedy konkretny dzień w określonym miejscu faktycznie się zaczyna. Ta klasa działa tylko w zwykłych ogólnych 24-godzinnych dniach, a nie w rzeczywistych dniach. Dla prawdziwych dni, należy określić strefę czasową: ZonedDateTime zdt = now.atStartOfDay( ZoneId.of( "Asia/Tokyo" ) ) ;. Niektóre dni w niektórych miejscach mogą rozpoczynać się o innej godzinie, na przykład o godzinie 01:00, z powodu anomalii, takich jak czas letni (DST).
Basil Bourque

35

Aby otrzymać ostatni dzień jako obiekt Date:

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

Date lastDayOfMonth = cal.getTime();

22

Możesz ustawić kalendarz na pierwszy dzień następnego miesiąca, a następnie odjąć dzień.

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

Po uruchomieniu tego kodu nextNotifTime zostanie ustawiony na ostatni dzień bieżącego miesiąca. Pamiętaj, że jeśli dzisiaj jest ostatni dzień miesiąca, efekt netto tego kodu jest taki, że obiekt Calendar pozostaje niezmieniony.


17

Poniższe zawsze zapewniają prawidłowe wyniki:

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

Dlaczego jest to konieczne? Czy możesz mi powiedzieć :)
Frank Fang

1
Tak, po prostu testy zakończyły się niepowodzeniem z tego dokładnego powodu powyżej. Problem polega na tym, że jeśli DAY_OF_MONTH nie jest ustawiony, domyślnie będzie bieżący.
ppearcy

7

Korzystanie z najnowszej java.timebiblioteki tutaj jest najlepszym rozwiązaniem:

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

Alternatywnie możesz:

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


2

Spójrz na getActualMaximum(int field)metodę obiektu Calendar.

Jeśli ustawisz obiekt kalendarza na miesiąc, dla którego szukasz ostatniej daty, getActualMaximum(Calendar.DAY_OF_MONTH)poda ci ostatni dzień.


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

Wdrożenie rozszerzenia daty Kotlin przy użyciu 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
}

Możesz wywołać toEndOfMonthfunkcję dla każdego obiektu Date, takiego jakDate().toEndOfMonth()


4
Te okropne klasy zostały wyparte lata temu przez nowoczesne klasy java.time wraz z przyjęciem JSR 310. Sugerowanie tych klas starszych w 2019 roku jest kiepską radą.
Basil Bourque

To nie jest zła rada. Nowoczesne java.time jest dostępne dla Androida tylko dla API 26+. Nadal polegamy na java.util. *, Gdy obsługujemy (nie tak) stare urządzenia.
Rafael Chagas
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.