2

Calendar.set() を使用して、特定の日付値の時間の始まりを返すコードがあります。2012 年 11 月 4 日日曜日 (東部タイムゾーン - EDT から EST への切り替え) に次の問題が発生しました。

public void testStartOfHourDST1() {
    
    Calendar cal = Calendar.getInstance();
    
    long time = 1352005200000L; // Nov 4, 2012, 1AM EDT
    cal.setTimeInMillis(time);
        
    cal.set(Calendar.MILLISECOND, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MINUTE, 0);

    System.out.println(new Date(time));
    System.out.println(new Date(cal.getTimeInMillis()));
    System.out.println(System.getProperty("java.version"));
            
    assertEquals(cal.getTimeInMillis(), time); // fails
    
    return;
}

出力:

2012 年 11 月 4 日 (日) 01:00:00 EDT

日 11 月 04 日 01:00:00 EST 2012

1.6.0_35

おそらく、これはカレンダーを使用する正しい方法ではありませんが、次の 1 時間 (または前の時間) に同じテストを実行すると問題なく動作します。これは JVM の問題ですか?

ありがとう

4

2 に答える 2

5

それは決定論的であり、プログラムされたとおりに実行するという意味で、実際には問題ではありません。2 つの午前 1 時のうち早い方を選択したい場合は問題です。

カレンダーのフィールドを変更すると、「米国/東部の午前 1 時」という情報のみが表示されます。さて、あなたのタイムゾーンにはその日の午前 1 時が 2 つありましたが、どちらを選ぶべきでしょうか? OpenJDK の作成者は、このあいまいさが提示された場合、常にそれを標準時間で後のものとして解釈するという決定を下しました。このコメントは、java.util.GregorianCalendar OpenJDK 6 からのものです。

    // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
    //    can be in standard or DST.  Both are valid representations (the rep
    //    jumps from 1:59:59 DST to 1:00:00 Std).
    //    Again, we assume standard time.

数値の実際の値を印刷すると、実際にはcal.getTimeInMillis()の値から 1 時間変更されていることがわかりますtime

于 2012-11-07T23:12:17.657 に答える
0

正しいタイムゾーンを取得することは非常に重要です。たとえば、ご存じのとおり、システムの現在のミリ秒単位の時間は、1970 年 1 月 1 日の午前 0 時から測定されます。これは十分に文書化されています。Date コンストラクタ JavaDoc は次のように述べています。

公開日(ロングデート)

Date オブジェクトを割り当て、それを初期化して、「エポック」と呼ばれる標準の基本時刻 (1970 年 1 月 1 日 00:00:00 GMT) からの指定されたミリ秒数を表します。

これは問題ありませんが、最初はこのプログラムの出力が少しわかりにくくなります。

import java.util.Date;
import java.util.TimeZone;
import java.text.SimpleDateFormat;

public class Demo {
    public static void main(String[] args) {
        TimeZone tz = TimeZone.getTimeZone("Europe/London");
        Date d = new Date(-3600000);

        SimpleDateFormat df = new SimpleDateFormat("MMMM dd, yyyy HH:mm:ss.SSS z");
        df.setTimeZone(tz);
        System.out.println(String.format("%8dms -> %s",
                    Long.valueOf(d.getTime()) ,df.format(d)));

        d.setTime(0);
        System.out.println(String.format("%8dms -> %s",
                    Long.valueOf(d.getTime()) ,df.format(d)));
   }
}

出力は次のとおりです。

-3600000ms -> January 01, 1970 00:00:00.000 GMT
       0ms -> January 01, 1970 01:00:00.000 GMT

ご覧のとおり、エポックは明らかに 1 時間ずれています。

そうでないことを除いて。「GMT」タイムゾーンを明示的に使用すれば、すべて問題ありません。「ヨーロッパ/ロンドン」のタイムゾーンは、そのように単純にトリッキーです.

カレンダーを操作するときは、使用しているタイム ゾーンを理解してください。

于 2012-11-08T00:42:43.460 に答える