2015-11-02 21 views
6

Bei einem nächtlichen Build von Jenkins fiel einer unserer Tests um 2:00:12 Uhr aus. Nach einiger Zeit Debugging und Änderung der Systemzeit meines Computers war ich sehr verwirrt. Dann schrieb ich den folgenden Test (Simulation des Problems), der fehlschlägt, aber ich kann nicht verstehen, warum. Ich habe Google ausprobiert, aber nichts ähnliches gefunden.
Kann jemand erklären, warum die letzte Behauptung fehlschlägt?Verwirrender Test fehlgeschlagen - Sommerzeit

@Test 
public void testFirstBeforeSecond_atDayLightSavingTime() throws ParseException { 
    Date first = new SimpleDateFormat("dd-MM-yyyy HH:mm").parse("25-10-2015 00:59"); 
    Date second = new SimpleDateFormat("dd-MM-yyyy HH:mm").parse("25-10-2015 01:01"); 
    assertThat(first.before(second), is(true)); // Ok, as expected 

    first = add(first, Calendar.HOUR_OF_DAY, 2); 
    second = add(second, Calendar.HOUR_OF_DAY, 2); 
    assertThat(first.before(second), is(true)); // Ok, as expected 

    first = add(first, Calendar.DAY_OF_YEAR, 2); 
    second = add(second, Calendar.DAY_OF_YEAR, 2); 
    assertThat(first.before(second), is(true)); // Fails? 
} 

private Date add(Date date, int field, int amount) { 
    Calendar calendar = Calendar.getInstance(); 
    calendar.setTimeZone(TimeZone.getTimeZone("Europe/Brussels")); 
    calendar.setTime(date); 
    calendar.add(field, amount); 
    return calendar.getTime(); 
} 

(In Brüssel Zeitzone, beendet die Sommerzeit auf 25-10-15 um 3 Uhr morgens. Die Uhr dann um eine Stunde zurücksprang.)

+0

Sie definieren nie eine TimeZone! Auf jedem Gerät, auf dem dieser Code ausgeführt wird, wird die Standardzeitzoneneinstellung des Hostsystems verwendet. Ihr lokaler Computer läuft normalerweise in lokaler Zeit und Server oft in UTC. Hast du darüber nachgedacht? –

+0

Möglicherweise im Zusammenhang mit http://stackoverflow.com/questions/13611108/problems-with-java-daylight-savings-time – dkatzel

+1

@ReneM. Zeitzone wird in der privaten Methode 'add' festgelegt:' calendar.setTimeZone (TimeZone.getTimeZone ("Europe/Brussels")); ' – Manu

Antwort

7

Wenn Sie bei jedem Schritt auszudrucken first und second hier ist der Weg, was Sie bekommen:

Ihre erste matchup

Sun Oct 25 00:59:00 CEST 2015 
Sun Oct 25 01:01:00 CEST 2015 

ist das genau ist, wie erwartet. Zwei Mal im Abstand von zwei Minuten während der mitteleuropäischen Sommerzeit.

Das zweite Matchup wird interessant. Sie fügten zwei Stunden zu jedem Datum hinzu:

Sun Oct 25 02:59:00 CEST 2015 
Sun Oct 25 02:01:00 CET 2015 

Jetzt überspannen die zwei Zeiten die DST Umschaltung. Das erste Mal ist während der Sommerzeit, 2:59; Das zweite Mal ist während der Standardzeit um 2:01 Uhr.

Wenn Sie zwei Tage, um es hinzuzufügen, es sieht aus wie Java alles über die Sommerzeit vergisst:

Tue Oct 27 02:59:00 CET 2015 
Tue Oct 27 02:01:00 CET 2015 

2:59 und 02.01 Uhr, genau so, wie es war ... diese zwei Tage später sein könnte durch den Kalender, aber das erste Mal ist sicherlich nicht 48 Stunden später als Schritt zwei!

Wenn Sie die letzten Sätze von Ergänzungen

first = add(first, Calendar.HOUR_OF_DAY, 48); 
    second = add(second, Calendar.HOUR_OF_DAY, 48); 

dann das Problem verschwindet ändern:

Tue Oct 27 01:59:00 CET 2015 
Tue Oct 27 02:01:00 CET 2015 

Meine Vermutung ist, dass die Java-Designer hatten einige Vermutungen über das erwartete Verhalten machen von was "N Tage später" bedeutet, wenn sich das über eine DST-Umschaltung erstreckt.

+0

... und natürlich gibt es keine "richtige" Lösung, es gibt nur zwei falsche Lösungen und Sie müssen eine auswählen. – biziclop

+0

Nun, die Java-Entwickler haben sich entschieden, die Addition von Tagen so zu interpretieren, dass die lokale Zeit unverändert bleibt - und den Offset zur Standardzeit ändern.Wird jedoch der Offset geändert, verschiebt sich der Zeitpunkt in diesem Fall um eine Stunde, was dazu führt, dass das erste Datum das zweite Datum überschreitet. Im ersten Fall: 1 Tag = 25 Stunden, im zweiten Fall: 1 Tag = 24 Stunden. –