なぜこの2回(1927年)を引くと変な結果になるのか?

java date timezone


以下のプログラムを実行すると、1秒間隔で時刻を参照している2つの日付文字列を解析して比較します。

public static void main(String[] args) throws ParseException {
    SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
    String str3 = "1927-12-31 23:54:07";  
    String str4 = "1927-12-31 23:54:08";  
    Date sDt3 = sf.parse(str3);  
    Date sDt4 = sf.parse(str4);  
    long ld3 = sDt3.getTime() /1000;  
    long ld4 = sDt4.getTime() /1000;
    System.out.println(ld4-ld3);
}

出力は次のとおりです。

353

なぜ ld4-ld31 ではなく(時間の1秒の差から予想されるように)、 353 ですか?

日付を1秒後の時間帯に変更すると

String str3 = "1927-12-31 23:54:08";  
String str4 = "1927-12-31 23:54:09";  

その場合、 ld4-ld31 になります。


Javaバージョン:

java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Dynamic Code Evolution Client VM (build 0.2-b02-internal, 19.0-b04-internal, mixed mode)
Timezone(`TimeZone.getDefault()`):

sun.util.calendar.ZoneInfo[id="Asia/Shanghai",
offset=28800000,dstSavings=0,
useDaylight=false,
transitions=19,
lastRule=null]

Locale(Locale.getDefault()): zh_CN



Answer 1 Jon Skeet


12月31日の上海での時間帯変更です。

上海での1927年の詳細については、このページを参照してください。基本的に1927年の終わりの真夜中に、時計は5分52秒戻りました。したがって、「1927-12-31 23:54:08」は実際には2回発生し、Javaがそのローカル日付/時刻の可能な最も遅い時刻として解析しているように見えるため、違いがあります。

奇妙で素晴らしい時間帯の世界での別のエピソードです。

編集:プレスを止めて!歴史の変化...

TZDBのバージョン2013aで再構築した場合、元の質問はまったく同じ動作を示しません。2013aでは、結果は358秒になり、遷移時間は23:54:08ではなく23:54:03になります。

野田タイムでユニットテストの形でこのような質問を収集しているため、これに気づきました。テストは変更されましたが、表示されるだけです。履歴データでさえ安全ではありません。

編集:歴史は再び変わりました...

TZDB 2014fでは、変更の時間は1900-12-31に移動し、現在は343秒の変更にすぎません(つまり、 tt+1 の間の時間は344秒です。

編集: 1900年の移行に関する質問に答えるために... Javaタイムゾーン実装はすべてのタイムゾーンを1900 UTCの開始前の任意の瞬間の標準時間にあるものとして扱うように見えます:

import java.util.TimeZone;

public class Test {
    public static void main(String[] args) throws Exception {
        long startOf1900Utc = -2208988800000L;
        for (String id : TimeZone.getAvailableIDs()) {
            TimeZone zone = TimeZone.getTimeZone(id);
            if (zone.getRawOffset() != zone.getOffset(startOf1900Utc - 1)) {
                System.out.println(id);
            }
        }
    }
}

上記のコードでは、Windowsマシンで出力が生成されません。したがって、1900年の初めに標準以外のオフセットを持つタイムゾーンは、それを遷移としてカウントします。TZDB自体にはそれより前に遡るデータがあり、「固定」標準時間(これは getRawOffset が有効な概念であると想定している時間)の概念に依存していないため、他のライブラリではこの人工的な遷移を導入する必要はありません。




Answer 2 Michael Borgwardt


現地時間の不連続が発生しました:

現地標準時が1928年1月1日(日)になろうとしていた時、0時00分00秒の時計が0時05分52秒に逆戻りして31日(土)になりました。1927年12月、23:54:08現地標準時の代わりに

これは特に不思議なことではなく、政治的または行政的な行動のためにタイムゾーンが入れ替わったり、変更されたりしたために、ある時期または別の時期に、ほとんどの場所で起こっています。




Answer 3 Raedwald


この奇妙さの教訓は

  • 日付と時間は可能な限りUTCで使用してください。
  • 日付や時間をUTCで表示できない場合は、常にタイムゾーンを表示してください。
  • UTCでの入力日時を要求できない場合は、タイムゾーンを明示的に指定する必要があります。



Answer 4 PatrickO


時間をインクリメントする場合は、UTCに変換してから加算または減算する必要があります。表示にはローカルタイムのみを使用します。

このようにして、何時間、何分が二度起こるかわからない期間を歩くことができるようになります。

UTCに変換した場合は、1秒ごとに追加し、現地時間に変換して表示します。あなたは11時54分08秒午後通過するでしょうLMT -午後11:59:59 LMT、その後、11時54分08秒午後CST -午後11:59:59 CST。




Answer 5 Rajshri


それぞれの日付を変換するのではなく、以下のコードを使用します。

long difference = (sDt4.getTime() - sDt3.getTime()) / 1000;
System.out.println(difference);

そして、その結果を見てください。

1