This page is under translation...
Come calcolare la differenza fra due date in Java?
Una domanda che sento porre periodicamente ed alla quale raramente è
risposto con chiarezza, forse anche a causa della documentazione relativa
alle classi java.util.Date e java.util.GregorianCalendar
che in alcuni punti lascia un po' a desiderare.
Nella documentazione troviamo che il metodo getTime() della
classe java.util.Date, oppure il metodo getTimeInMillis()
della classe java.util.GregorianCalendar, ritorna il numero
di millisecondi a partire dall'epoca 1 Gennaio 1970 00:00:00.000 GMT
(Gregoriano). Ciò che invece è omesso è che sia
getTime() che getTimeInMillis() nel ritornare
il numero di millisecondi tengono conto: degli anni bisestili e dei
cambi d'ora legale e solare.
Uno dei modi più intuitivi per calcolare i giorni di differenza che intercorrono fra due date è il seguente.
Definiamo le due date dallaData < allaData :
GregorianCalendar dallaData = null; GregorianCalendar allaData = null;
convertiamole in millisecondi:
long dallaDataMilliSecondi = dallaData.getTimeInMillis(); long allaDataMilliSecondi = allaData.getTimeInMillis();
calcoliamone la differenza:
long millisecondiFraDueDate = allaDataMilliSecondi - dallaDataMilliSecondi;
ed infine convertiamo i millisecondi di differenza in giorni, utilizzando la divisione fra interi:
//1 giorno = 1000*60*60*24 ms // = 86400000 ms double giorniFraDueDate = millisecondiFraDueDate / 86400000;
L'errore commesso nel convertire, da millisecondi a giorni, la differenza fra le due date consiste nell'aver implicitamente supposto che ogni giorno duri 24 ore. Sotto tale ipotesi, infatti, la divisione fra interi darebbe effettivamente i giorni di differenza fra due date. In realtà l'ipotesi è errata poichè non tutti i giorni durano 24 ore. Infatti chiamati:
osserviamo che Gls dura 23 ore, mentre Gls dura 25 ore.
Ecco che la divisione fra interi da un risultato errato nel caso i millisecondi di differenza non siano un multiplo intero di 24 ore. Invece che affermare che ogni giorno duri 24 ore è più corretto asserire che il giorno medio in un anno dura 24 ore. La media su 365 giorni da esattamente 24 ore poichè l'ora in meno del Gls è compensata dall'ora in più del Gsl:
1^ Gls Gsl 365^ 24 ... 24 23 24 ... 24 25 24 ... 24
Il Gsl del 2005 cade il 27/03 e provando a calcolare, con la
divisione intera, i giorni che intercorrono dalla data 27/03/2005 alla
data 28/03/2005 si ottiene il risultato giorniFraDueDate = 0.0.
Risultato sorprendente per chi pensa che ogni giorno duri 24 ore.
Tuttavia la divisione intera tronca le 23 ore, pari a circa 0.9 giorni,
così sembra che ci siano zero giorni fra il 27 ed il 28.
Ricalcolando i giorni di differenza fra il 27/03/2005 ed il 28/03/2005 con la divisione fra reali:
//1 giorno medio = 1000*60*60*24 ms // = 86400000 ms double giorniFraDueDate = millisecondiFraDueDate / 86400000.0;
otteniamo che giorniFraDueDate = 0.9583333333333334 pari
a 23.0000000000000016 ore.
Analogamente il Gls del 2005 cade il 30/10 e provando a calcolare, con
la divisione intera, i giorni che intercorrono dalla data 30/10/2005 alla
data 31/10/2005 si ottiene il risultato giorniFraDueDate = 1.0.
Risultato corretto per chi pensa che ogni giorno duri 24 ore.
Ricalcolando i giorni di differenza fra il 30/10/2005 ed il 31/10/2005
con la divisione fra reali otteniamo che
giorniFraDueDate = 1.0416666666666667 pari a
25.0000000000000008 ore.
Con la divisione fra interi nel calcolare la differenza fra due date si perde un giorno se fra di esse è compreso almeno un Gsl. In tutti gli altri casi il calcolo è corretto.
Con la divisione fra reali vengono introdotti dei decimali nella differenza fra due date quando fra di esse è compreso un Gsl, oppure un Gls. Mentre non vengono introdotti decimali se fra le due date cadono sia il Gsl che il Gls, poichè l'ora in meno del Gls è compensata dall'ora in più del Gsl.
Per generalizzare i risultati ottenuti, per la divisione fra reali, a due date appartenenti ad anni diversi si può pensare al tempo come ad un susseguirsi di periodi, nei quali vige l'ora solare (winter time) o l'ora legale (summer time), intervallati da giorni di cambio d'ora:
... oraSolare Gsl oraLegale Gls oraSolare Gsl oraLegale ...
I giorni di differenza fra due date sono un numero intero se queste ultime appartengono ad uno stesso tipo di periodo (Solare o Legale) poiché contengono un numero pari di coppie Gsl Gls. Mentre i giorni di differenza fra due date sono un numero razionale se queste ultime appartengono a diversi tipi di periodo (Solare o Legale) poiché, oltre a contenere un numero pari di coppie Gsl Gls, contengono anche un solo Gsl, oppure un solo Gls.
Una fra le soluzioni possibili è quella di arrotondare il risultato della conversione in giorni calcolato con la divisione fra reali:
//1 giorno medio = 1000*60*60*24 ms // = 86400000 ms double giorniFraDueDate = Math.round( millisecondiFraDueDate / 86400000.0 );
Calcola i giorni di differenza fra un giorno ed il giorno immediatamente successivo. Il calcolo è ripetuto per tutte le coppie successive di date dal 01/01/2003 alla 31/12/2006. Interessanti i risultati per i giorni Gsl e Gls:
]da , a ] int real round ]27/03/04, 28/03/04] 1.0 1.0 1.0 ]28/03/04, 29/03/04] 0.0 0.9583333334 1.0 ]29/03/04, 30/03/04] 1.0 1.0 1.0 ... ]30/10/04, 31/10/04] 1.0 1.0 1.0 ]31/10/04, 01/11/04] 1.0 1.0416666667 1.0 ]01/11/04, 02/11/04] 1.0 1.0 1.0
Scarica il codice sorgente di DifferenzaDate1.java:
Calcola i giorni di differenza fra due date: la prima è fissata al 01/01/2003, la seconda parte dal giorno successivo e viene incrementata fino al 31/12/2006. Interessanti i risultati per i giorni Gsl e Gls:
]da , a ] int real round ]01/01/03, 30/03/03] 88.0 88.0 88.0 ]01/01/03, 31/03/03] 88.0 88.958333333 89.0 ]01/01/03, 01/04/03] 89.0 89.958333333 90.0 ... ]01/01/03, 26/10/03] 297.0 297.95833333 298.0 ]01/01/03, 27/10/03] 299.0 299.0 299.0 ]01/01/03, 28/10/03] 300.0 300.0 300.0
Scarica il codice sorgente di DifferenzaDate2.java:
Per chi volesse approfondire l'argomento rimando ai link:
Copyright © 2003, 2008 Tarin Gamberini
Last updated 20/01/2008