2015-11-02 18 views
6

In una struttura notturna di Jenkins, uno dei nostri test è fallito alle 2:00:12 del mattino. Dopo un po 'di tempo per il debug e la modifica del tempo di sistema del mio computer, ero molto confuso. Poi ho scritto il seguente test (simulando il problema), che fallisce, ma non riesco a capire perché. Ho provato Google, ma non ho trovato nulla di simile.
Qualcuno può spiegare perché l'ultima affermazione fallisce?Confusione test fallita - ora legale

@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(); 
} 

(A Bruxelles il fuso orario, l'ora legale è concluso il 25-10-15 alle 3 del mattino. L'orologio poi saltò indietro di un'ora.)

+0

Non si definisce mai un fuso orario! Pertanto, su qualsiasi dispositivo che esegue questo codice viene utilizzata l'impostazione predefinita del fuso orario del sistema host. Il tuo computer locale è normalmente in esecuzione in ora locale e server spesso in UTC. Hai pensato a questo? –

+0

Possibilmente correlato a http://stackoverflow.com/questions/13611108/problems-with-java-daylight-savings-time – dkatzel

+1

@ReneM. Il fuso orario è impostato nel metodo privato 'add':' calendar.setTimeZone (TimeZone.getTimeZone ("Europe/Brussels")); ' – Manu

risposta

7

Se si stampa first e second ad ogni passo del modo in cui, ecco quello che si ottiene:

il tuo primo matchup è

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

che è esattamente come previsto. Due volte, a due minuti di distanza, durante l'estate dell'Europa centrale.

Il secondo abbinamento diventa interessante. Hai aggiunto due ore a ciascuna data:

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

Ora le due volte si estendono il passaggio all'ora legale. La prima volta è durante l'estate, 2:59; la seconda volta è durante l'ora solare, alle 2:01.

Quando si aggiungono due giorni ad esso, sembra che Java dimentica tutto il periodo estivo:

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

2:59 e 2:01, esattamente com'era ... questo potrebbe essere due giorni dopo dal calendario, ma la prima volta non è certamente 48 ore più tardi del secondo passaggio!

Se si modificano i set finali di aggiunte al

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

allora il problema va via:

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

La mia ipotesi è che i progettisti di Java hanno dovuto fare alcune ipotesi circa il comportamento atteso di cosa significa "N giorni dopo" quando si estende a un passaggio all'ora legale.

+0

... e ovviamente non esiste una soluzione "corretta", ci sono solo due soluzioni sbagliate e devi sceglierne una. – biziclop

+0

Bene, i progettisti Java hanno deciso di interpretare l'aggiunta di giorni in modo che l'ora locale sia mantenuta invariata e di modificare l'offset in base all'ora standard.Ma cambiando l'offset si sposta l'istantanea in avanti di un'ora in questo caso, causando quindi la prima data che supera la seconda data. Nel primo caso: 1 giorno = 25 ore, nel secondo caso: 1 giorno = 24 ore. –

Problemi correlati