월말 계산


144

다음 달 마지막 날이 발송 예정인 알림에 대한 계산에 문제가 있습니다.

내 코드는 다음과 같습니다.

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

이것이 내가 믿는 문제를 일으키는 선입니다.

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

캘린더를 사용하여 다음 달의 마지막 날을 올바르게 설정하려면 어떻게해야합니까?


1
다음 달의 첫날로 설정 한 다음 하루를 롤백하십시오.
Bill

SSCCE는 쉽게이 질문에 대답 할 것입니다. 실제로 어떤 문제가 발생합니까?
DNA

답변:


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

현재 달의 실제 최대 값을 반환합니다. 예를 들어 지금은 윤년의 2 월이므로 29를로 반환합니다 int.


고마워, 나는 다음 달에 최대치를 얻어야하지만, 그 부분이 지금 작동하기 때문에 여전히 그 달의 첫날이 될 수 있어야합니다. 시간과 노력에 다시 한번 감사드립니다
OakvilleWork

4
ActualMaximum모든 날짜 를 얻는 것은 문제가되지 않습니다 . 전화하기 전에 달력 인스턴스를 필요한 날짜로 롤링하십시오 getActualMaximum. 첫 데이트는 다음과 같이하실 수 있습니다getActualMinimum()
AlexR

알렉스 감사합니다. 인스턴스를 한 달 앞당겨서 그 달의 getActualMaximum을 찾으려면 어떻게해야합니까 ?? 건배
OakvilleWork

이것이 Alex입니까? nextNotifTime.roll (Calendar.MONTH, true); 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

61

java.time.temporal.TemporalAdjusters.lastDayOfMonth ()

은 Using java.time자바 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

당신은 시간 정보를 추가해야하는 경우, 당신은 가능한을 사용할 수 있습니다 LocalDateLocalDateTime같은 변환

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

좋은 답변입니다. 그러나 마지막 부분은 약하므로 사용을 제안합니다 LocalDateTime. 이 클래스에는 표준 시간대 또는 UTC에서 오프셋 개념이 없습니다. 따라서 특정 장소에서 특정 날짜가 실제로 시작되는시기를 결정할 수 없습니다. 이 수업은 실제 일이 아닌 일반 일반 24 시간 동안 만 작동합니다. 실제로는 시간대를 지정하십시오 ZonedDateTime zdt = now.atStartOfDay( ZoneId.of( "Asia/Tokyo" ) ) ;. 일광 절약 시간제 (DST)와 같은 예외로 인해 일부 장소에서 며칠은 01:00과 같은 다른 시간에 시작될 수 있습니다.
Basil Bourque

35

그리고 마지막 날을 Date 객체로 얻으려면 :

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

Date lastDayOfMonth = cal.getTime();

22

다음 달 1 일로 캘린더를 설정 한 다음 하루를 뺄 수 있습니다.

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

이 코드를 실행하면 nextNotifTime이 현재 달의 마지막 날로 설정됩니다. 오늘이 그 달의 마지막 날인 경우이 코드의 효과는 Calendar 객체가 변경되지 않은 상태입니다.


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

왜 필요한가요? :)
Frank Fang

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)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
이 끔찍한 클래스는 JSR 310을 채택한 현대 java.time 클래스에 의해 몇 년 전에 대체 되었습니다. 2019 년에 이러한 레거시 클래스를 제안하는 것은 좋지 않습니다.
Basil Bourque

나쁜 조언이 아닙니다. 최신 java.time 은 API 26 이상에서만 Android에서 사용할 수 있습니다. 우리는 오래된 장치를 지원할 때 여전히 java.util. * 에 의존 합니다.
라파엘 차 가스
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.