4

javaDateTimeと methodを使用して、特定の開始日から 1 か月を追加しようとしましたplusMonths()

開始時間が月の初めにある場合、すべてが期待どおりに機能します。

DateTime startOfMonth = new DateTime(2013, 1, 1, 00, 00, 00);
    System.out.println(startOfMonth.toString());
    for (int i = 0; i < 12; i++) {
        startOfMonth = startOfMonth.plusMonths(1);
        System.out.println(startOfMonth.toString());
}

出力は予想どおり毎月 1 日で、すべてが素晴らしいです!

2013-01-01T00:00:00.000+01:00
2013-02-01T00:00:00.000+01:00
2013-03-01T00:00:00.000+01:00
2013-04-01T00:00:00.000+02:00
2013-05-01T00:00:00.000+02:00
2013-06-01T00:00:00.000+02:00
2013-07-01T00:00:00.000+02:00
2013-08-01T00:00:00.000+02:00
2013-09-01T00:00:00.000+02:00
2013-10-01T00:00:00.000+02:00
2013-11-01T00:00:00.000+01:00
2013-12-01T00:00:00.000+01:00
2014-01-01T00:00:00.000+01:00

しかし、例を月末に変更すると、必要なものが返されません!

System.out.println("");
DateTime endOfMonth = new DateTime(2012, 12, 31, 23, 59, 59);
System.out.println(endOfMonth.toString());
for (int i = 0; i < 12; i++) {
    endOfMonth = endOfMonth.plusMonths(1);
    System.out.println(endOfMonth.toString());
}

これは以下を返します:

2012-12-31T23:59:59.000+01:00
2013-01-31T23:59:59.000+01:00
2013-02-28T23:59:59.000+01:00
2013-03-28T23:59:59.000+01:00
2013-04-28T23:59:59.000+02:00
2013-05-28T23:59:59.000+02:00
2013-06-28T23:59:59.000+02:00
2013-07-28T23:59:59.000+02:00
2013-08-28T23:59:59.000+02:00
2013-09-28T23:59:59.000+02:00
2013-10-28T23:59:59.000+01:00
2013-11-28T23:59:59.000+01:00
2013-12-28T23:59:59.000+01:00

では、なぜ"2013-02-28T23:59:59.000+01:00"プラス 1 か月ではないの"2013-03-31T23:59:59.000+01:00"でしょうか。この3日間はどこですか?

4

9 に答える 9

7

日付操作の問題は、月によって日数が異なることです。1 月は 31 日、2 月は 28 日しかありません。1 月 31 日に「1 か月」を追加すると、ソフトウェアは何を達成したいかを推測できないため、2 月 31 日になる月を増分します。無効です。次のステップは、あなたが見ているこれらの奇妙な結果をもたらす日付を調整することです.

注: 元の Java Date クラスでは、1 月に 1 か月を追加すると 3 月 2 日または 3 日になりますが、これは正確には良くありません :-)

月末を反復する正しい方法は、その月の最初の日を反復し、1 日 (または 1 ミリ秒) を減算することです。

DateTime startOfMonth = new DateTime(2013, 1, 1, 00, 00, 00);
System.out.println(startOfMonth.toString());
for (int i = 0; i < 12; i++) {
    startOfMonth = startOfMonth.plusMonths(1);
    DateTime endOfMonth = startOfMonth.minusDays(1); // magic here
    System.out.println(startOfMonth + "-" + endOfMonth);
}

[start,end)日付範囲だけが必要な場合endは、常に月の初日であるハーフ オープン範囲を使用します。

于 2013-11-01T09:11:19.063 に答える
4

2013 年 2 月には 28 日しかないため、1 か月後に追加すると、毎月 28 日のままになります。

これはドキュメントで指定されています:

計算は、月の同じ日を保持する月フィールドのみを変更するために最善を尽くします。ただし、特定の状況では、より小さなフィールドを変更する必要がある場合があります。たとえば、2007-03-31 に 1 か月を加えても 2007-04-31 にはならないため、月の日は 2007-04-30 に調整されます。

于 2013-11-01T09:07:36.533 に答える
1

上記のコメントで述べたように、月の最後の日を取得する Joda の方法は、dayOfMonth プロパティで最大値を取得することです。

public static void endOfMonth() {
    DateTime startOfMonth = new DateTime(2013, 1, 1, 00, 00, 00);

    for (int i = 0; i < 12; i++) {
        int lastDay = startOfMonth.dayOfMonth().getMaximumValue();
        System.out.println(startOfMonth.withDayOfMonth(lastDay).toString());

        startOfMonth = startOfMonth.plusMonths(1);
    }
}

これにより、次が生成されます。

2013-01-31T00:00:00.000-06:00
2013-02-28T00:00:00.000-06:00
2013-03-31T00:00:00.000-05:00
2013-04-30T00:00:00.000-05:00
2013-05-31T00:00:00.000-05:00
2013-06-30T00:00:00.000-05:00
2013-07-31T00:00:00.000-05:00
2013-08-31T00:00:00.000-05:00
2013-09-30T00:00:00.000-05:00
2013-10-31T00:00:00.000-05:00
2013-11-30T00:00:00.000-06:00
2013-12-31T00:00:00.000-06:00
于 2013-11-03T04:38:55.843 に答える
1

半開き

あなたの質問は、通常、「ハーフオープン」アプローチを使用して時間の範囲を追跡するのが最善である理由の例です。Half-Open (表記: [)) では、時間範囲が含まれる場合は始まりが終わりが含まない場合。したがって、「月」とは、その月の最初の日の最初の瞬間を意味し、翌月の最初の日の最初の瞬間までは実行されますが、これは含まれません

Joda-Time ライブラリは、このような時間のスパンを表すクラス Interval を提供します。

DateTimeZone timeZone = DateTimeZone.forID( "Europe/Zurich" );
DateTime firstOfYear = new DateTime( 2013, 1, 1, 0, 0, 0, timeZone ).withTimeAtStartOfDay();
Interval month01_Interval = new Interval( firstOfYear, firstOfYear.plusMonths( 1 ).withTimeAtStartOfDay() );

実行時:

month01_Interval : 2013-01-01T00:00:00.000+01:00/2013-02-01T00:00:00.000+01:00
于 2014-05-06T07:21:57.470 に答える
0

これは私にとってはうまくいきます:

public static void main(String[] args) {
    Calendar endOfMonth = Calendar.getInstance();
    endOfMonth.set(Calendar.DAY_OF_MONTH, 31);
    endOfMonth.set(Calendar.MONTH, 11);
    endOfMonth.set(Calendar.YEAR, 2012);

    endOfMonth.set(Calendar.HOUR_OF_DAY, 23);
    endOfMonth.set(Calendar.MINUTE, 59);
    endOfMonth.set(Calendar.SECOND, 59);
    endOfMonth.set(Calendar.MILLISECOND, 59);

    System.out.println(endOfMonth.getTime());
    for (int i = 0; i < 12; i++) {
        endOfMonth.add(Calendar.MONTH, 1);

        if(i >= 2){
            endOfMonth.add(Calendar.MONTH, 1);
            endOfMonth.set(Calendar.DAY_OF_MONTH, 1);
            endOfMonth.add(Calendar.DAY_OF_MONTH, -1);
        }

        System.out.println(endOfMonth.getTime());
    }
}

結果は次のとおりです。

Mon Dec 31 23:59:59 GMT+04:00 2012
Thu Jan 31 23:59:59 GMT+04:00 2013
Thu Feb 28 23:59:59 GMT+04:00 2013
Sun Mar 31 23:59:59 GMT+04:00 2013
Tue Apr 30 23:59:59 GMT+04:00 2013
Fri May 31 23:59:59 GMT+04:00 2013
Sun Jun 30 23:59:59 GMT+04:00 2013
Wed Jul 31 23:59:59 GMT+04:00 2013
Sat Aug 31 23:59:59 GMT+04:00 2013
Mon Sep 30 23:59:59 GMT+04:00 2013
Thu Oct 31 23:59:59 GMT+04:00 2013
Sat Nov 30 23:59:59 GMT+04:00 2013
Tue Dec 31 23:59:59 GMT+04:00 2013
于 2013-11-01T10:00:08.920 に答える
0

月をインクリメントする前に 1 日を追加し、その後に 1 日を減算します。

new DateTime(date).plusDays(1).plusMonths(months).minusDays(1).toDate()
于 2014-06-18T06:27:11.840 に答える