2

現在の日付 (つまり、// 2013-03-10 00:00:00) のみを表す GregorianCalendar を java.util.Date オブジェクトに変換する際の問題をトラブルシューティングしています。このテストの背後にある考え方は、2 つの日付を取得することです。1 つは現在の日付のみ、もう 1 つは現在の時刻のみ (つまり、// 1970-01-01 12:30:45) で、日付を表す 1 つの日付に結合します。時間 (2013-03-10 12:30:45)。

DST 切り替えが発生した日に、テストは失敗しました。これは、GregorianCalendar を日付オブジェクト (Date date = dateCal.getTime(); 以下のコードで) に変換すると 1 時間が失われ、(2013-03-09 にロールバックされた) ためです。 23:00:00)。これを起こさないようにするにはどうすればよいですか?

public static Date addTimeToDate(Date date, Date time) {
    if (date == null) {
        throw new IllegalArgumentException("date cannot be null");
    } else if (time == null) {
        throw new IllegalArgumentException("time cannot be null");
    } else {
        Calendar timeCal = GregorianCalendar.getInstance();
        timeCal.setTime(time);

        long timeMs = timeCal.getTimeInMillis() + timeCal.get(Calendar.ZONE_OFFSET) + timeCal.get(Calendar.DST_OFFSET);
        return addMillisecondsToDate(date, timeMs);
    }
}


@Test
public void testAddTimeToDate() {
    Calendar expectedCal = Calendar.getInstance();
    Calendar dateCal = Calendar.getInstance();
    dateCal.clear();
    dateCal.set(expectedCal.get(Calendar.YEAR), expectedCal.get(Calendar.MONTH), expectedCal.get(Calendar.DAY_OF_MONTH));

    Calendar timeCal = Calendar.getInstance();
    timeCal.clear();
    timeCal.set(Calendar.HOUR_OF_DAY, expectedCal.get(Calendar.HOUR_OF_DAY));
    timeCal.set(Calendar.MINUTE, expectedCal.get(Calendar.MINUTE));
    timeCal.set(Calendar.SECOND, expectedCal.get(Calendar.SECOND));
    timeCal.set(Calendar.MILLISECOND, expectedCal.get(Calendar.MILLISECOND));

    Date expectedDate = expectedCal.getTime();
    Date date = dateCal.getTime();
    Date time = timeCal.getTime();

    Date actualDate = DateUtil.addTimeToDate(date, time);

    assertEquals(expectedDate, actualDate);
}
4

4 に答える 4

0

これが、DSTによる時間の損失/増加を補うためにメソッドをリファクタリングすることになった方法です。

public static Date addTimeToDate(Date date, Date time) {
    if (date == null) {
        throw new IllegalArgumentException("date cannot be null");
    } else if (time == null) {
        throw new IllegalArgumentException("time cannot be null");
    } else {
        Calendar dateCal = GregorianCalendar.getInstance();
        dateCal.setTime(date);

        Calendar timeCal = GregorianCalendar.getInstance();
        timeCal.setTime(time);
        int zoneOffset = timeCal.get(Calendar.ZONE_OFFSET);

        if (dateCal.get(Calendar.MONTH) == Calendar.MARCH) {
            if (Calendar.SUNDAY == dateCal.get(Calendar.DAY_OF_WEEK) && dateCal.get(Calendar.DAY_OF_MONTH) >= 7
                    && dateCal.get(Calendar.DAY_OF_MONTH) <= 14 && timeCal.get(Calendar.HOUR_OF_DAY) >= 3) {
                zoneOffset -= TimeUnit.MILLISECONDS.convert(1, TimeUnit.HOURS);
            }
        } else if (dateCal.get(Calendar.MONTH) == Calendar.NOVEMBER) {
            if (Calendar.SUNDAY == dateCal.get(Calendar.DAY_OF_WEEK) && dateCal.get(Calendar.DAY_OF_MONTH) <= 7
                    && timeCal.get(Calendar.HOUR_OF_DAY) >= 3) {
                zoneOffset += TimeUnit.MILLISECONDS.convert(1, TimeUnit.HOURS);
            }
        }
        long timeMs = timeCal.getTimeInMillis() + zoneOffset + timeCal.get(Calendar.DST_OFFSET);
        return addMillisecondsToDate(date, timeMs);
    }
}

DSTのルールが変更された場合は、このメソッドを更新する必要があるため、このメソッドは好きではありません。同様の機能を実行するライブラリはありますか?

于 2013-03-19T14:56:13.957 に答える
0

試してみましたが、違いはありませんでした。さまざまなロケールでさえ、GregorianCalendarをCalendarに置き換えました。

使用済み:

private static Date addMillisecondsToDate(Date date, long timeMs) {
    return new Date(date.getTime() + timeMs);
}

今後のJava8では、日付と時刻のサポートが改善されます。

于 2013-03-14T15:17:50.537 に答える
0

タイムゾーンのオフセットを計算に含めているのはなぜですか? Java でミリ秒を扱う場合、それらは常にUTC です。追加の変換を行う必要はありません。

あなたの最大の問題は、おそらくこれらの日付/時刻の計算を手動で行おうとすることです。計算を処理するには、Calendar クラス自体を使用する必要があります。

于 2013-03-14T14:46:28.167 に答える