月末日計算


144

次の月末日が送信予定の通知の計算に問題があります。

これが私のコードです:

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

これは私が信じている問題を引き起こす行です:

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

カレンダーを使用して、翌月の最終日に通知を適切に設定するにはどうすればよいですか?


1
翌月の最初の日に設定してから、1日ロールバックします。
ビル

A SSCCEは、それが簡単にこの質問に答えるためになるだろう。実際にどのような問題が発生していますか?
DNA

回答:


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

これは、今月の実際の最大値を返します。たとえば、現在はうるう年の2月なので、29をとして返しますint


おかげで、次の月の最大値を取得する必要がありますが、その部分が現在機能しているため、月の初日になることもできるように機能する必要があります。あなたの時間と努力に再び感謝します
オークビル

4
ActualMaximum毎回入手しても問題ありません。を呼び出す前に、カレンダーインスタンスを必要な日付にロールバックするだけですgetActualMaximum。最初の日付はgetActualMinimum()
AlexR

OK、アレックスに感謝します。インスタンスを1か月先に進めて、その月のgetActualMaximumを確認したい場合はどうすればよいですか?歓声
OakvilleWork

これはアレックスでしょうか?nextNotifTime.roll(Calendar.MONTH、true); nextNotifTime.getActualMaximum(Calendar.DAY_OF_MONTH);
オークビル

また、この後に準備日時を設定しました。nextNotification.setReadyDateTime(nextNotifTime.getTime()); そのため、代わりにこれを行わないでくださいnextNotifTime.roll(Calendar.MONTH, true); nextNotifTime.getActualMaximum(Calendar.DAY_OF_MONTH); nextNotifTime.setTime(Calendar.DAY_OF_MONTH);
オークビル

61

java.time.temporal.TemporalAdjusters.lastDayOfMonth()

java.timeJava 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からのオフセットの概念がありません。したがって、特定の場所の特定の日が実際にいつ始まるかを判断することはできません。このクラスは、一般的な24時間の日に対してのみ機能し、実際の日では機能しません。実際の日には、タイムゾーンを指定しますZonedDateTime zdt = now.atStartOfDay( ZoneId.of( "Asia/Tokyo" ) ) ;。夏時間(DST)などの異常のため、場所によっては01:00などの別の時間に始まる日もあります。
バジルブルク

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オブジェクトが変更されないままであることを覚えておいてください。


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 2015年

7

java.timeここで最新のライブラリを使用することが最善の解決策です。

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

または、次のようにすることもできます。

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


2

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
これらのひどいクラスは、数年前にJSR 310を採用した最新のjava.timeクラスに取って代わられました。2019年にこれらのレガシークラスを提案することは、あまりお勧めできません
バジルブルク

それは悪いアドバイスではありません。最新のjava.timeは、API 26+のAndroidでのみ使用できます。古いデバイスをサポートする場合(そうではない)は、依然としてjava.util。*に依存しています。
Rafael Chagas
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.