2016-06-29 8 views
6
TimeZone.setDefault(TimeZone.getTimeZone("BET")); 
Locale.setDefault(Locale.ENGLISH); 

SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS zzzz"); 

Date d0 = sdf1.parse("2037-10-17 23:00:00.000"); 
Date d1 = sdf1.parse("2037-10-17 23:00:00.001"); 
Date d2 = sdf1.parse("2037-10-17 23:59:59.999"); 
Date d3 = sdf1.parse("2037-10-18 00:00:00.000"); 
Date d4 = sdf1.parse("2037-10-18 00:00:00.001"); 
Date d5 = sdf1.parse("2037-10-18 00:59:59.999"); 
Date d6 = sdf1.parse("2037-10-18 01:00:00.000"); 
Date d7 = sdf1.parse("2037-10-18 01:00:00.001"); 
Date d8 = sdf1.parse("2037-10-18 01:59:59.999"); 
Date d9 = sdf1.parse("2037-10-18 02:00:00.000"); 

System.out.println(sdf2.format(d0) + "(" + d0.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d0) + ", offset: " + TimeZone.getDefault().getOffset(d0.getTime())); 
System.out.println(sdf2.format(d1) + "(" + d1.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d1) + ", offset: " + TimeZone.getDefault().getOffset(d1.getTime())); 
System.out.println(sdf2.format(d2) + "(" + d2.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d2) + ", offset: " + TimeZone.getDefault().getOffset(d2.getTime())); 
System.out.println(sdf2.format(d3) + "(" + d3.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d3) + ", offset: " + TimeZone.getDefault().getOffset(d3.getTime())); 
System.out.println(sdf2.format(d4) + "(" + d4.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d4) + ", offset: " + TimeZone.getDefault().getOffset(d4.getTime())); 
System.out.println(sdf2.format(d5) + "(" + d5.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d5) + ", offset: " + TimeZone.getDefault().getOffset(d5.getTime())); 
System.out.println(sdf2.format(d6) + "(" + d6.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d6) + ", offset: " + TimeZone.getDefault().getOffset(d6.getTime())); 
System.out.println(sdf2.format(d7) + "(" + d7.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d7) + ", offset: " + TimeZone.getDefault().getOffset(d7.getTime())); 
System.out.println(sdf2.format(d8) + "(" + d8.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d8) + ", offset: " + TimeZone.getDefault().getOffset(d8.getTime())); 
System.out.println(sdf2.format(d9) + "(" + d9.getTime() + "), dst: " + TimeZone.getDefault().inDaylightTime(d9) + ", offset: " + TimeZone.getDefault().getOffset(d9.getTime())); 

die löschteBrasilia Sommerzeit-Übergang am 2037-10-18

2037-10-17 23:00:00.000 Brasilia Time(2139444000000), dst: false, offset: -10800000 
2037-10-17 23:00:00.001 Brasilia Time(2139444000001), dst: false, offset: -10800000 
2037-10-17 23:59:59.999 Brasilia Time(2139447599999), dst: false, offset: -10800000 
2037-10-18 01:00:00.000 Brasilia Summer Time(2139447600000), dst: true, offset: -7200000 
2037-10-18 00:00:00.001 Brasilia Time(2139447600001), dst: true, offset: -10800000 
2037-10-18 00:59:59.999 Brasilia Time(2139451199999), dst: true, offset: -10800000 
2037-10-18 01:00:00.000 Brasilia Summer Time(2139447600000), dst: true, offset: -7200000 
2037-10-18 00:00:00.001 Brasilia Time(2139447600001), dst: true, offset: -10800000 
2037-10-18 00:59:59.999 Brasilia Time(2139451199999), dst: true, offset: -10800000 
2037-10-18 02:00:00.000 Brasilia Summer Time(2139451200000), dst: true, offset: -7200000 

Dieser Code Druck um dem das Datum mal out "2037.10.18 00: 00: 000 Brasilia Time", Das Ergebnis zeigt, dass "2037-10-18 00: 00: 000 Brasilia Time" "2037-10-18 01: 00: 00.000 Brasilia Summer Time" sein sollte, was bedeutet, dass Brasilia in diesem Moment in die Sommerzeit kam.

Meine Frage ist, warum zwischen "2037-10-18 00: 00: 00.001 Brasilia Time" und "2037-10-18 00: 59: 59.999 Brasilia Time" der Zeitzonen-Offset noch Standard-Zeitversatz verwendet. Ist das ein Fehler in JDK-Zeitzonendaten oder funktioniert diese Zeitzone tatsächlich auf diese Weise?

Mein Code verwendet Offset, um zu entscheiden, ob ein dst-Übergang zwischen zwei Daten vorliegt. Offensichtlich "2037-10-18 01: 00: 00.000 Brasilia Summer Time" und "2037-10-18 00: 59: 59.999 Brasilia Time" funktionieren diese beiden Daten hier nicht.

Ich kann ändern, um "TimeZone.getDefault(). InDaylightTime (Date date)" zu verwenden, um zu entscheiden, ob es einen Übergang gibt, aber ich möchte immer noch wissen, ob es ein Bug von JDK ist.

+0

Wenn es einen Fehler gibt, ist es wahrscheinlich im Parser, da 'd3' und' d6' (sowie 'd4/7' und' d5/8') auf den gleichen langen Wert analysiert werden. – Thomas

+0

Welche Java Version und Olson TZDB Version? –

+0

Es kann ein Fehler sein - die java.time API scheint [die richtigen Ergebnisse] zu geben (http://ideone.com/XHmdwY). – assylias

Antwort

0

Ich habe versucht, mit einem Debugger durch den Code zu gehen und es scheint ein Problem mit der Zeitzone und dem Schalter selbst zu sein: BRT zu BRST wechselt von 00:00:00 zu 01:00:00 um Mitternacht, was bedeutet eine Stunde dazwischen existiert eigentlich nicht.

Aus meiner Debuggen des Problems scheint in GregorianCalendar#computeTime() vor allem in der folgenden Zeile zu sein:

millis -= zoneOffsets[0] + zoneOffsets[1]; 

Vor dieser Linie millis ist die Zeit seit Epoche, die aus dem analysierten Zeitpunkt berechnet wurde und die für 00:00:00 unterscheidet (213946800000) und 01:00:00 (2139440400000). In beiden Fällen ist zoneOffsets[0] -10800000, was der Rohoffset zu UTC ist. Der Unterschied ist in zoneOffsets[1]: für 00:00:00 ist es 0, aber für 01:00:00 ist 3600000, d.h. 1 Stunde. Der Grund dafür scheint ein interner Aufruf an inDaylightTime(new Date(millis)) zu sein, der für 00:00:00 (vor-dst) false zurückgibt, aber für 01:00:00 (was die erste Stunde von dst ist) wahr ist. Daher ist die Endzeit die gleiche, da Sie immer 10800000 Millis hinzufügen, aber 3600000 Millis vom höheren Wert abziehen, der um 3600000 Millis höher ist :)

Am Ende erhalten Sie eine Date mit der gleichen Milli-Zeit.

Beim Formatieren des Datums scheint es so zu sein, dass der Formatierer die Milli-Zeit gegen die Zeitzone prüft und jedes Mal, dass 00:00:00,000 - 59:59:59,999 entspricht, dh in beiden Zeitzonen könnte eine dstOffset von 0 angenommen werden 3600000 und damit verschiedene Zeitzonen werden gedruckt.

bearbeiten: wenn 01:00:00.000 und 01:00:00.001 Vergleich scheint es, als ob es könnte ein Fehler in ZoneInfo.getOffsets(time, offsets, type) sein, die einen dst von 360.000 für die ehemaligen und 0 für die letztere, während Offset zurück, wenn innerhalb der Formatierer die Felder des Kalenders Füllung beide werden dst übernehmen.

Bearbeiten 2: Wenn Sie das Parser-Format ändern, um Zeitzonen-Verknüpfungen zu akzeptieren, können Sie das gleiche Verhalten beobachten, d.00:00:00.000 BRT und 01:00:00.000 BRST werden zu 2139447600000 geparst und erneut zu 01:00:00.000 BRST formatiert, während 00:00:00.001 BRT und 01:00:00.001 BRST zu 2139447600001 geparst und zu 00:00:00.001 BRT formatiert werden - was an sich korrekt ist.