-1

Java での SimpleTimeZone クラスの使用に問題があります。まず、JavaDoc は優れていますが、開始ルールと終了ルールに関して理解するのは簡単ではありません。しかし、ウェブで見つかったいくつかの例の助けを借りて、私はそれを正しくすることができました(なぜ8がday_of_monthで月の第2週を表すのかまだわかりません!!!しかし何でも)

今、私が理解していることを検証するための簡単な Junit テストを作成しました。

package test;

import static org.junit.Assert.assertEquals;

import java.sql.Timestamp;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.SimpleTimeZone;

import org.apache.log4j.Logger;
import org.junit.Test;



public class SimpleTimeZoneTest {

Logger log = Logger.getLogger(SimpleTimeZoneTest.class);

@Test   
public void testTimeZoneWithDST() throws Exception {


    Calendar testDateEndOut = new GregorianCalendar(2012, Calendar.NOVEMBER, 4, 01, 59, 59);
    Calendar testDateEndIn = new GregorianCalendar(2012, Calendar.NOVEMBER, 4, 02, 00, 00);
    Calendar testDateStartOut = new GregorianCalendar(2012, Calendar.MARCH, 11, 01, 59, 59);
    Calendar testDateStartIn = new GregorianCalendar(2012, Calendar.MARCH, 11, 02, 00, 00);

    SimpleTimeZone est = new SimpleTimeZone(-5 * 60 * 60 * 1000, "EST");
    est.setStartRule(Calendar.MARCH, 8, -Calendar.SUNDAY, 2 * 60 * 60 * 1000);
    est.setEndRule(Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);

    Calendar theCal = new GregorianCalendar(est);

    theCal.setTimeInMillis(testDateEndOut.getTimeInMillis());

    log.info(" Cal date = " + new Timestamp(theCal.getTimeInMillis()) + " : " + theCal.getTimeZone().getDisplayName());
    log.info(" Cal use DST = " + theCal.getTimeZone().useDaylightTime());
    log.info(" Cal In DST = " + theCal.getTimeZone().inDaylightTime(theCal.getTime()));
    log.info("offset = " + theCal.getTimeZone().getOffset(theCal.getTimeInMillis()));
    log.info("DTS offset= " + theCal.getTimeZone().getDSTSavings());
    assertEquals("End date Should be In DST", true, theCal.getTimeZone().inDaylightTime(theCal.getTime()));

    theCal.setTimeInMillis(testDateEndIn.getTimeInMillis());

    log.info(" Cal date = " + new Timestamp(theCal.getTimeInMillis()) + " : " + theCal.getTimeZone().getDisplayName());
    log.info(" Cal use DST = " + theCal.getTimeZone().useDaylightTime());
    log.info(" Cal In DST = " + theCal.getTimeZone().inDaylightTime(theCal.getTime()));
    log.info("offset = " + theCal.getTimeZone().getOffset(theCal.getTimeInMillis()));
    log.info("DTS offset= " + theCal.getTimeZone().getDSTSavings());
    assertEquals("End date Should be Out DST", false, theCal.getTimeZone().inDaylightTime(theCal.getTime()));

    theCal.setTimeInMillis(testDateStartIn.getTimeInMillis());

    log.info(" Cal date = " + new Timestamp(theCal.getTimeInMillis()) + " : " + theCal.getTimeZone().getDisplayName());
    log.info(" Cal use DST = " + theCal.getTimeZone().useDaylightTime());
    log.info(" Cal In DST = " + theCal.getTimeZone().inDaylightTime(theCal.getTime()));
    log.info("offset = " + theCal.getTimeZone().getOffset(theCal.getTimeInMillis()));
    log.info("DTS offset= " + theCal.getTimeZone().getDSTSavings());
    assertEquals("Start date Should be in DST", true, theCal.getTimeZone().inDaylightTime(theCal.getTime()));

    theCal.setTimeInMillis(testDateStartOut.getTimeInMillis());

    log.info(" Cal date = " + new Timestamp(theCal.getTimeInMillis()) + " : " + theCal.getTimeZone().getDisplayName());
    log.info(" Cal use DST = " + theCal.getTimeZone().useDaylightTime());
    log.info(" Cal In DST = " + theCal.getTimeZone().inDaylightTime(theCal.getTime()));
    log.info("offset = " + theCal.getTimeZone().getOffset(theCal.getTimeInMillis()));
    log.info("DTS offset= " + theCal.getTimeZone().getDSTSavings());
    assertEquals("Start date Should be Out DST", false, theCal.getTimeZone().inDaylightTime(theCal.getTime()));





}

}

わかりました。日付制限をテストして、inDaylightTime が正しい値を返すかどうかを確認したいと思います。

したがって、私のルールは次のとおりです。

DST は 3 月の第 2 日曜日の午前 2 時に開始します DST は 11 月の第 1 日曜日の午前 2 時に終了します

2012 年 (現在) では、これにより 3 月 11 日の午前 2 時と 11 月 4 日の午前 2 時が得られます。

私のテスト日が適切に設定されていることがわかります!!!

さて、ここに私のテスト実行の出力があります:

2012-11-01 18:22:44,344 INFO [test.SimpleTimeZoneTest] - < Cal date = 2012-11-04 01:59:59.0 : Eastern Standard Time>
2012-11-01 18:22:44,345 INFO [test.SimpleTimeZoneTest] - < Cal use DST = true>
2012-11-01 18:22:44,345 INFO [test.SimpleTimeZoneTest] - < Cal In DST = false>
2012-11-01 18:22:44,345 INFO [test.SimpleTimeZoneTest] - <offset = -18000000>
2012-11-01 18:22:44,345 INFO [test.SimpleTimeZoneTest] - <DTS offset= 3600000>

私の最初のアサートは単に失敗し、2012-11-04 01:59:59 が DST にないことを教えてくれます... !!!!???

2012-11-04 00:59:59 と入力すると、テストに合格しました。

この 1 時間のギャップは私を困惑させます... 誰かこの動作を説明できますか?

ああ、ところで、誰かが詳しく説明できれば:

est.setStartRule(Calendar.MARCH, 8, -Calendar.SUNDAY, 2 * 60 * 60 * 1000);

なぜ 8 は 3 月の第 2 週を意味するのか...そして -SUNDAY. 実際のカレンダーの例では、このことを理解できません!!!

ありがとう

4

2 に答える 2

2

私の最初のアサートは単に失敗し、2012-11-04 01:59:59 が DST にないことを教えてくれます... !!!!???

11 月 4 日の午前 2:00 に、午前 1:00 に "フォールバック" するため、時刻 1:59:59 は DST 内と DST 後の 2 回発生します。したがって、このステートメント:

Calendar testDateEndOut =
    new GregorianCalendar(2012, Calendar.NOVEMBER, 4, 01, 59, 59);

本当に曖昧です。たまたま、JDK は1:59:59の2 番目のオカレンス、つまり DST の外にあるものを参照していると判断します。これが、その結果が表示されている理由です。

編集して追加:最初に 00:00:00 に設定してから、目的の量だけ前に移動するように書き込むことで、このあいまいさを取り除き、最初の出現を確実に取得できます。testDateEndOuttestDateEndOut.setTimeInMillis (testDateEndOut.getTimeInMillis() + 7199000L)

ああ、ところで、誰かが詳しく説明できれば:

est.setStartRule(Calendar.MARCH, 8, -Calendar.SUNDAY, 2 * 60 * 60 * 1000);

なぜ 8 は 3 月の第 2 週を意味するのか...そして -SUNDAY.

java.util.SimpleTimeZoneはさまざまなケースをサポートしているため、いくつかの魔法を使用します。の 4 引数バージョンをsetStartRule使用しているため、引数は次のようになります。

  • startMonth- あなたはすでにこれを理解しています。MARCH3月を意味します。
  • startDay- 注: 週ではなく日です。8月の 8 日を意味します。
  • startDayOfWeek- 負の値を使用して、上記で指定した日付以降の日付を指定した場合。-SUNDAYその日以降の日曜日を意味します。
  • startTime- あなたはこれを理解しています。

全体として、(Calendar.MARCH, 8, -Calendar.SUNDAY, 2 * 60 * 60 * 1000)3 月 8 日以降の最初の日曜日の午前 2:00 を意味します。

于 2012-11-01T22:59:05.047 に答える
1

他のすべてをチェックしたわけではありませんが、最初の問題は、すべてのCalendar値をデフォルトのタイムゾーンで作成していることです...つまり、次のように書くと:

theCal.setTimeInMillis(testDateEndOut.getTimeInMillis());

...それはすでにシステムのデフォルトのタイムゾーンを適用しています。

theCal完全に削除して、コードを次のように変更することを強くお勧めします。

SimpleTimeZone est = new SimpleTimeZone(-5 * 60 * 60 * 1000, "EST");
est.setStartRule(Calendar.MARCH, 8, -Calendar.SUNDAY, 2 * 60 * 60 * 1000);
est.setEndRule(Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);

Calendar testDateEndOut = new GregorianCalendar(est);
testDateEndOut.set(2012, Calendar.NOVEMBER, 4, 01, 59, 59);
Calendar testDateEndIn = new GregorianCalendar(est);
testDateEndIn.set(2012, Calendar.NOVEMBER, 4, 02, 00, 00);
Calendar testDateStartOut = new GregorianCalendar(est);
testDateStartOut.set(2012, Calendar.MARCH, 11, 01, 59, 59);
Calendar testDateStartIn = new GregorianCalendar(est);
testDateStartIn.set(2012, Calendar.MARCH, 11, 02, 00, 00);

これで問題が解決するわけではないかもしれませんが、少なくとも問題についての推論が容易になります。

別の方法として、UTC でカレンダーを使用し、DST 移行の前後のUTCインスタントを使用してタイム ゾーンをテストすることもできます。

他のことは別として、すべての日付/時刻の作業ではなく、Joda Timeを使用することを強くお勧めします。java.util.*これははるかに優れた API ですが、ドキュメントDateTimeZoneBuilderも少し扱いに​​くい場合があります。

于 2012-11-01T22:49:07.780 に答える