8

タイムゾーンを認識する必要がある Java アプリがあります。Unix エポック時間を取得し、それをタイムスタンプに変換して Oracle SQL 呼び出しに使用しようとすると、正しいタイムゾーンが取得されますが、タイムゾーンの「useDaylightTime」値が正しくありません。つまり、現在「true」を返しています。 、私たちが DST にいないとき (私は TZ "America/New_York" のフロリダにいます)。

これは Red Hat Linux Enterprise 6 で実行されており、私が知る限り、タイムゾーン正しく設定されています。たとえば、'date' は次のように返します。

また、「zdump」ユーティリティを使用して、「isdst」の現在の値が 0 であることも確認できます。

私の Java バージョンは 1.6.0_31 です。

私はこれをグーグルで検索し、これが引き起こした多くの問題を見てきましたが、それらの多くは単純に TZ を手動で設定するように言っていますが、私の問題は TZ ではなく、デフォルトの TZ の「isDaylight」が「true」に設定されているという事実です。 . これにより、クエリが 1 時間ずれたデータを返すようになっていると思います (そうであることがわかります)。

可能な限り簡単な方法でこれを再現するために実行した簡単なコードを次に示します。

public class TZdefault {

    public static void main(String[] args) throws IOException {

            long startTime = System.currentTimeMillis()/1000;

            Calendar start = Calendar.getInstance();
            start.setTimeInMillis(startTime);

            start.setTimeZone(TimeZone.getDefault());

            System.out.println("Start UTC: " + start + "ms: " + start.getTimeInMillis());
            System.out.println("use daylight: " + start.getTimeZone().useDaylightTime());

    } // end main


}  // end class

最後に 1 つ。コードで TZ を「EST」に設定すると、もちろん、「isDaylight」が False に設定された TZ が返されますしかし、それは良い解決策ではありません。

隠したいと思っていた詳細を追加したかったのです。

TIMEZONE フィールドで TIMESTAMP を使用する Oracle 11g データベースにレコードがあります。2 つのパラメータが BETWEEN 開始タイムスタンプと終了タイムスタンプを使用している JDBC クエリを実行しているだけです。

このテーブルにクエリを実行するとき、カレンダー エントリを使用する準備済みステートメントを使用しています。その唯一の目的は、タイムゾーンを操作することでした。肝心なのは、「デフォルト」のタイムゾーンが適用された後、開始時間と終了時間に「getTimeInMillis」メソッドを使用して pstmt.setTimestamp() 呼び出しを行っていることです。ログ出力は、実際には正しいミリ秒を入れていることを示していますが、返された SQL 結果は明らかに正確に 1 時間ずれています!

データ挿入側にも問題がないか検証中です。

しかし、多くのデバッグ情報があり、JDBC クエリで正しい時刻を要求しているようです。

4

4 に答える 4

13

タイムゾーンのuseDaylightTime値が正しくありません。つまり、現在 DST ではないのに「true」を返しています。

useDaylightTimeと混同していると思いますinDaylightTime。前者は、将来、夏時間と標準時間の間に移行があるかどうかを示します。移行のどちら側にいるのかではありません。たとえば、中国では夏時間が調整されないため、中国のタイム ゾーンでは false が返されますが、米国のほとんどの州 (アリゾナ州を除く) では夏時間が採用されているため、ほとんどの米国のタイム ゾーンでは true が返されます。

inDaylightTime

public abstract boolean inDaylightTime(Date date)

指定された日付がこのタイム ゾーンのサマー タイムに含まれているかどうかを問い合わせます。

useDaylightTime

public abstract boolean useDaylightTime()

この TimeZone が夏時間を使用するかどうかを照会します。基礎となる TimeZone 実装サブクラスが過去および将来の夏時間スケジュールの変更をサポートしている場合、このメソッドは、将来の予測である可能性があり、現在の規則と同じではない可能性がある最後の既知の夏時間規則を参照します。observesDaylightTime()現在のルールも考慮する必要がある場合は、呼び出しを検討してください。

于 2012-11-28T18:10:08.377 に答える
5

夏時間の計算を無効にする場合は、タイムゾーンを EST に設定する必要があります。それ以外の場合、時間はAMERICA/NEW_YORKに設定されたデフォルトのタイムゾーンに基づいて計算されます

       TimeZone zoneEST = TimeZone.getTimeZone("EST"); 
       System.out.println(zoneEST.getDSTSavings());  //0 hour
       System.out.println(zoneEST.getRawOffset());  //5 hour
       TimeZone.setDefault(zoneEST);
       System.out.println("");

       TimeZone zoneNY = TimeZone.getTimeZone("America/New_York");
       System.out.println(zoneNY.getDSTSavings()); // 1 hour
       System.out.println(zoneNY.getRawOffset()); // 5 hour
于 2012-11-28T18:04:13.800 に答える
3

夏時間を確実に無視する方法を見つけました

TimeZone tz = TimeZone.getTimeZone("GMT");
TimeZone.setDefault(tz);
GregorianCalendar calendar;
calendar = new GregorianCalendar();

GregorianCalendar オブジェクトを作成する前にタイムゾーンを設定する

于 2014-05-24T23:25:33.980 に答える
0
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class TimeZoneTest {
    public static void main(String[] argv) throws ParseException {

        SimpleDateFormat formatter = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");

        String dateInString = "22-01-2015 10:15:55 AM";
        Date date = formatter.parse(dateInString);
        TimeZone tz = TimeZone.getDefault();

        // From TimeZone Asia/Singapore
        System.out.println("TimeZone : " + tz.getID() + " - " + tz.getDisplayName());
        System.out.println("TimeZone : " + tz);
        System.out.println("Date : " + formatter.format(date));

        // To TimeZone America/New_York
        SimpleDateFormat sdfAmerica = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");
        TimeZone tzInAmerica = TimeZone.getTimeZone("America/New_York");
        sdfAmerica.setTimeZone(tzInAmerica);

        String sDateInAmerica = sdfAmerica.format(date); // Convert to String first
        Date dateInAmerica = formatter.parse(sDateInAmerica);

        System.out.println("\nTimeZone : " + tzInAmerica.getID() + 
                                      " - " + tzInAmerica.getDisplayName());
        System.out.println("TimeZone : " + tzInAmerica);
        System.out.println("Date (String) : " + sDateInAmerica);
        System.out.println("Date (Object) : " + formatter.format(dateInAmerica)); 
    }

}
于 2015-04-15T10:39:01.617 に答える