Restar dos fechas en Java correctamente
Octubre 28, 2009 • Fechas Java, Java • Comments
Buenas,
Ya estoy de nuevo otra vez. Siento el retraso, no es que haya abandonado el blog
, he estado super liado con cursos en la empresa y la verdad que no me ha permitido dedicarme mucho al blog.
Hoy vamos hablar de nuevo sobre las fechas en Java, es un tema tan amplio que pienso que aun me quedan múchisimos posts para escribir sobre el tema.
Veamos, este Post en concreto, tiene mucho que ver con el anterior que escribí sobre fechas: como utilizar correctamente las fechas en Java. ¿Por qué? Porque es realmente importante utilizar las herramientas que proporciona Java para las fechas, ya que a veces cuyas herramientas tienen en cuenta factores que nosotros no podemos controlar, como ejemplo podéis leer el Post del link anterior y lo comprobaréis con vuestros ojos.
Hoy voy a explicar una cosa que me he dejado en todos los Posts de Java que he escrito anteriormente, y que omití (perdonadme):
¿Qué herramienta utilizar para restar dos fechas en Java? ¿Qué utilizar para obtener la diferencia entre dos fechas en java?
Yo recomiendo, plenamente, utilizar el GregorianCalendar. Es lo que comentaba antes, hay que utilizar las herramientas de Java destinadas a la solución/manejo del tema a tratar, en este caso las Fechas.
¿Por qué no utilizar la clase Date? Si miráis minuciosamente la API de la clase Date, podréis comprobar que muchos de los métodos están siendo Deprecated y SUN están dando más relevancia las clases Calendar, Gregorian Calendar, etc.
Con eso no quiero decir que funcione mejor o peor una Clase u otra, pero desde mi punto de vista siempre hay que utilizar las clases idóneas. Reitero, MI PUNTO DE VISTA.
¿Cómo restar dos fechas en Java? ¿Cómo obtener la diferencia entre dos fechas en Java?
Necesitamos los siguientes datos para calcular la resta:
- Tener dos objetos GregorianCalendar o Date (ya sea obtenidos con string, con Calendar, etc…)
- Efectuar operaciones matemáticas simples (como mucho una multiplicación) sin que intervengan los milisegundos
A este punto voy a dividirlo en dos subpuntos: restar fechas del mismo año o restar fechas de distinto año. Empecemos:
Restar dos Fechas en Java que son del mismo año
/*CREAMOS EL GREGORIAN CALENDAR DE LAS DOS FECHAS*/
GregorianCalendar t1 = new GregorianCalendar(2009,9,23);
GregorianCalendar t2 = new GregorianCalendar(2009,9,28);
/*RESTAR FECHAS*/
int dias = t2.get(Calendar.DAY_OF_YEAR) - t1.get(Calendar.DAY_OF_YEAR);
/*IMPRESION POR PANTALLA*/
System.out.println("Valor de días es: " + dias);
Están fácil como esto, RESTAR y PUNTO. Salida por pantalla es:
Valor de días es: 5
Se puede dar el caso de que necesitemos crear los dos objetos GregorianCalendar dados dos objetos Date. El código quedaría así:
/* CREAMOS LOS OBJETOS GREGORIAN CALENDAR PARA EFECTUAR LA RESTA */
GregorianCalendar date1 = new GregorianCalendar();
date1.setTime(dateIni); //dateIni es el objeto Date
GregorianCalendar date2 = new GregorianCalendar();
date2.setTime(dateFin); //dateFin es el objeto Date
¿Qué problemas puede conllevar esto?
Pues el problema está cuando cogemos dos fechas de distinto año, el problema que puede darse es que el número no sea el correcto o el que esperamos. Veamos como es la salida por pantalla de la resta de las fechas: 2009/12/25 y 2010/01/02 (teóricamente deberían ser 8 días):
Valor de días es: -357 //( si le restásemos 365 días que tiene el año daría
Restar dos Fechas en Java de diferente año
Gracias al comentario anterior, y buscando en san Google se me ocurrió la brillante idea (que buscando, buscando, también lo encontré en un foro inglés
) de hacer lo siguiente:
/*CREAMOS EL GREGORIAN CALENDAR DE LAS DOS FECHAS*/
GregorianCalendar date1 = new GregorianCalendar(2009,11,25);
GregorianCalendar date2 = new GregorianCalendar(2010,0,2);
/* COMPROBAMOS SI ESTAMOS EN EL MISMO ANYO */
if (date1.get(Calendar.YEAR) == date2.get(Calendar.YEAR)) {
System.out.println( "Valor de Resta simple: " +String.valueOf(date2.get(Calendar.DAY_OF_YEAR) - date1.get(Calendar.DAY_OF_YEAR)));
} else {
/* SI ESTAMOS EN DISTINTO ANYO COMPROBAMOS QUE EL ANYO DEL DATEINI NO SEA BISIESTO
* SI ES BISIESTO SON 366 DIAS EL ANYO
* SINO SON 365
*/
int diasAnyo = date1.isLeapYear(date1.get(Calendar.YEAR)) ? 366 : 365;
/* CALCULAMOS EL RANGO DE ANYOS */
int rangoAnyos = date2.get(Calendar.YEAR) - date1.get(Calendar.YEAR);
/* CALCULAMOS EL RANGO DE DIAS QUE HAY */
int rango = (rangoAnyos * diasAnyo) + (date2.get(Calendar.DAY_OF_YEAR) - date1.get(Calendar.DAY_OF_YEAR));
}
System.out.println("Valor de rangoDias:" + (date2.get(Calendar.DAY_OF_YEAR) - date1.get(Calendar.DAY_OF_YEAR)));
System.out.println("Valor de rangoAnyos: " + nAnyos);
System.out.println("Valor de rango: " + rango);
El resultado importante es el de rango, resultado por pantalla es:
Valor de rangoAnyos: -357
Valor de nAnyos: 1
Valor de diasCorrectos: 8
Fijáos que he tenido que controlar la opción del AÑO BISIESTO… que también se tiene que controlar. Si volvéis a mirar el código lo he solucionado con esta simple operacion:
int diasAnyo = date1.isLeapYear(date1.get(Calendar.YEAR)) ? 366 : 365;
También deseo remarcar que he realizado un IF para controlar si la resta se hace con fechas del mismo año o si son diferentes años
Cómo restar con la clase Date (MI OPINIÓN INCORRECTO)
Utilizando los milisegundos es problemático… desde mi punto de vista, INCORRECTO. Problemas con cambios de hora,…
Date actual = new Date();
Date fecha =null;
String dateFrom = "20091023";
SimpleDateFormat day= new SimpleDateFormat("yyyyMMdd");
try {
fecha = day.parse(dateFrom);
} catch (ParseException ex) {
ex.getMessage();
ex.printStackTrace();
}
long diferencia= ( fecha.getTime() - actual.getTime() );
System.out.println("Valor de diferencia: " + diferencia/(1000*60*60*24));
¿Es una opción viable? SÍ, menos cuando hay cambios de hora por el medio. Debemos ir con precaución y repito: mejor utilizar las clases Java preparadas para el problema en cuestión.
Espero que os haya servido de algo, al menos para solucionar algún problema o ayudaros a entender un poco más las fechas en Java.
ACTUALIZACIÓN
Actualizo este post por el mero echo que aNieto2K me ha sugerido que pusiera estadísticas
. Lo sé Andrés, tengo que currarmelo más jejeje.
