2016-01-22 2 views
5

Sto riscontrando un problema in Java che calcola la data corrente meno un certo numero di giorni.Java calcola la data passata da oggi sta andando nel futuro

ho:

Date pastDate = new Date(new Date().getTime() - (1000 * 60 * 60 * 24 * 25)); 

Questo sta tornando mar 16 febbraio 09:04:18 EST 2016 quando in realtà dovrebbe tornare mar 28 dicembre 16:06:11 EST 2015 (25 giorni in il passato).

Cosa c'è di molto strano è che per qualsiasi numero di sotto dei 25 giorni funziona tutto bene:

Date pastDate = new Date(new Date().getTime() - (1000 * 60 * 60 * 24 * 24)); 

Come nel 24 giorni nel passato restituisce un prevedibile gio 29 dic 16:06:11 EST 2015.

Qualsiasi aiuto sarebbe apprezzato.

+2

vi consiglio di andare oltre il [nuovo tutorial di dati in tempo] (http://docs.oracle.com/javase/tutorial/datetime/index.html). – user1803551

risposta

10

Con 24 giorni, il prodotto rimane appena sotto il massimo possibile valore int, Integer.MAX_VALUE, che è 2.147.483.647. Il prodotto 24 giorni è 2.073.600.000. Il prodotto 25 giorni è 2.160.000.000. Il risultato è overflow e un numero negativo, risultante in una data futura.

Per tali valori, utilizzare un valore letterale long per il primo valore (o trasmetterlo a long) per evitare l'overflow che eccede lo Integer.MAX_VALUE. Si noti la L allegata alla 1000L:

(1000L * 60 * 60 * 24 * 25) 

Questo funziona bene perché il desired constructor for Date takes a long.

L'aritmetica delle date viene gestita in modo più pulito utilizzando Calendar s, dove è possibile esplicitamente add un numero negativo di giorni.

Inoltre, con Java 8+, è possibile utilizzare Instant and its minus method per sottrarre l'ora.

Instant.now().minus(24, ChronoUnit.DAYS); 
+0

Oh wow, che errore bizzarro. Grazie, lo terrò a mente la prossima volta. Funziona perfettamente ora :). – StackPWRequirmentsAreCrazy

+0

Se stai eseguendo l'aritmetica in base a un numero di secondi o nanosecondi, potresti potenzialmente incorrere in problemi con secondi bisestili ... a causa dei secondi bisestili, il numero di secondi in ogni giorno non è sempre lo stesso. –

2

Non eseguire i propri calcoli di data e ora. Il lavoro in ufficio è un affare sorprendentemente difficile. Hai già eseguito l'errore int -versus- long comune con il calcolo dei millisecondi. Utilizzare una libreria data-decente decente. Fortunatamente Java ora viene fornito con la migliore libreria del settore.

java.time

Come accennato in the correct Answer by rgettman, si dovrebbe utilizzare il nuovo quadro java.time integrato in Java 8 e versioni successive. Le vecchie lezioni di data-ora in bundle con le prime versioni di Java sono notoriamente fastidiose.

Nozioni di base su java.time ... Un Instant è un momento sulla timeline in UTC. Applicare un fuso orario (ZoneId) per ottenere un ZonedDateTime.

Il fuso orario è fondamentale per determinare le date, poiché la data non è la stessa in tutto il mondo in qualsiasi momento. Un nuovo giorno sorge prima nell'est.

Instant instant = Instant.now(); // In UTC. 
ZoneId zoneId = ZoneId.of("Asia/Kolkata"); 
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant , zoneId); 
ZonedDateTime zdtTwentyFiveDaysAgo = zdt.minusDays(25); 

Si consiglia il primo momento della giornata per quella data in tempo di 25 giorni fa piuttosto poi il giorno tempo di corrente. Il primo momento non è sempre 00:00:00.0 a causa dell'ora legale (DST) e forse altre anomalie. Quindi lascia che java.time determini l'ora del giorno. Dobbiamo passare attraverso LocalDate e poi tornare a ZonedDateTime per ottenere il primo momento.

ZonedDateTime zdtTwentyFiveDaysAgoStart = zdtTwentyFiveDaysAgo.toLocalDate().atStartOfDay(zoneId);