2015-08-12 4 views
6

Sono di fronte a un comportamento strano di java.util.Calendar.Comportamento strano del calendario

Il problema è quando aggiungo una chiamata di metodo Calendar#getTime() in mezzo solo di quello che ricevo risultato corretto, ma quando ho direttamente ottengo il Dates della settimana senza chiamare Calendar#getTime() si riferisce alla prossima settimana invece di corrente settimana.

Si prega di considerare seguente frammento di codice:

public class GetDatesOfWeek { 

    public static void main(String[] args) { 

     SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); 

     Calendar cal = Calendar.getInstance(); 
     cal.set(1991, Calendar.DECEMBER, 11); 

     //System.out.println(cal.getTime());//LINE NO : 14 

     for(int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) { 
      cal.set(Calendar.DAY_OF_WEEK, i); 
      Date date = cal.getTime(); 
      System.out.println(sdf.format(date)); 
     } 
    } 

} 

Quando ho rimuovere il commento la linea non 14 ottengo seguente output:

Wed Dec 11 07:38:06 IST 1991 
08-12-1991 
09-12-1991 
10-12-1991 
11-12-1991 
12-12-1991 
13-12-1991 
14-12-1991 

Ma quando io commento che la linea ed eseguire il codice ottengo seguente risultato.

15-12-1991 
16-12-1991 
17-12-1991 
18-12-1991 
19-12-1991 
20-12-1991 
21-12-1991 

Si noti che in entrambi i casi il mese e l'anno campi sono propri, ma la data di inizio è stata spostata 08-12-1991-15-12-1991 per me 08-12-1991 è corretta.

La mia domanda:

  • perché sto ottenendo diverse date di settimana in questi due casi?
  • Perché questo tipo di funzionalità è fornito in Java?
+0

State facendo funzionare i due test in modo indipendente o avete il codice che viene eseguito loro uno dopo l'altro in un'unica esecuzione? – Jason

risposta

5

Se si passa attraverso il codice in un debugger, si vedranno cose interessanti accadere alle variabili interne dell'oggetto cal.

L'oggetto del calendario memorizza separatamente sia l'ora che rappresenta che i campi di regolazione. Dopo aver eseguito la riga 12, l'oggetto cal viene creato con l'ora corrente e nessun campo di regolazione e la sua variabile interna isTimeSet è impostata su true. Ciò significa che il tempo interno memorizzato è corretto.

L'esecuzione della riga 13 cancella isTimeSet su falso perché ora il tempo interno deve essere regolato dai campi di regolazione prima che sia di nuovo accurato. Ciò non avviene immediatamente, ma attende una chiamata a getTime() o get(...), getTimeInMillis(), add(...) o roll(...).

La riga 14 (se non commentata) forza il ricalcolo dell'ora interna utilizzando i campi di regolazione e imposta nuovamente la variabile isTimeSet su true.

La riga 17 imposta quindi un altro campo di regolazione e disattiva nuovamente la variabile isTimeSet.

La riga 18 ricalcola di nuovo l'ora corretta in base al campo di regolazione impostato nella riga 17.

La soluzione:

Il problema si verifica quando si combinano l'impostazione del giorno del mese con il giorno della settimana. Quando è impostato il giorno della settimana, l'impostazione del giorno del mese viene ignorata e il giorno corrente del mese nell'oggetto cal viene utilizzato come punto di partenza. Ti capita di ottenere una settimana a partire dal 15 perché la data odierna è il 12 e il 15 dicembre 1991 è la domenica più vicina al 12 dicembre 1991.

Nota: Se esegui di nuovo il test tra una settimana, lo farai ottieni un risultato diverso.

La soluzione è chiamare getTimeInMillis() o getTime() per forzare il ricalcolo del tempo prima di impostare le regolazioni del giorno della settimana.

Testing:

Se non volete aspettare una settimana per provare ancora una volta, provare quanto segue:

public class GetDatesOfWeek { 

    public static void main(String[] args) { 

     SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); 

     Calendar cal = Calendar.getInstance(); 
     cal.set(2015, Calendar.AUGUST, 1); // adjust this date and see what happens 
     cal.getTime(); 

     cal.set(1991, Calendar.DECEMBER, 11); 
     //System.out.println(cal.getTime());//LINE NO : 14 

     for(int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) { 
      cal.set(Calendar.DAY_OF_WEEK, i); 
      Date date = cal.getTime(); 
      System.out.println(sdf.format(date)); 
     } 
    } 

} 
+3

E questo è anche documentato nel documento Java ** I valori dei campi del calendario possono essere impostati chiamando i metodi impostati. Qualsiasi valore di campo impostato in un Calendario non verrà interpretato finché non sarà necessario calcolare il suo valore temporale (millisecondi da Epoch) oi valori dei campi del calendario. Chiamare get, getTimeInMillis, getTime, add and roll implica tale calcolo. ** – Codebender