0% encontró este documento útil (0 votos)
462 vistas4 páginas

Manejo de Fechas en Java I

1) El documento describe las clases Date y Calendar de Java que se usan para manejar fechas. 2) Explica que Date almacena milisegundos desde el 1 de enero de 1970 y las subclases SqlDate y Time representan fechas y horas respectivamente. 3) Detalla cómo convertir entre estas clases usando los milisegundos almacenados.
Derechos de autor
© Attribution Non-Commercial (BY-NC)
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
462 vistas4 páginas

Manejo de Fechas en Java I

1) El documento describe las clases Date y Calendar de Java que se usan para manejar fechas. 2) Explica que Date almacena milisegundos desde el 1 de enero de 1970 y las subclases SqlDate y Time representan fechas y horas respectivamente. 3) Detalla cómo convertir entre estas clases usando los milisegundos almacenados.
Derechos de autor
© Attribution Non-Commercial (BY-NC)
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 4

Manejo De Fechas En Java I

Por Carlos Zuluaga (Mayo 1 de 2007).

Trabajar con fechas en java no es algo del otro mundo ni tiene demasiadas complicaciones, pero la cantidad de
formas que hay para hacerlo puede confundirnos, o peor aún, puede que sólo conozcamos la más mala para
hacerlo. Con estos artículos pretendo explicar un poco que clases tiene el lenguaje para trabajar con fechas, los
métodos más usados y algunas sugerencias para realizar un trabajo adecuado que nos facilite el mantenimiento de
nuestras aplicaciones.

1. Las clases java.util.Date y java.sql.Date. Son dos de las clases más usadas cuando una aplicación implica el
trabajo con fechas:
java.util.Date: Según la documentación "La clase java.util.Date representa un instante de tiempo específico, con
precisión de milisegundos"; esto más que ser una especie de "autoadulación" para la clase, quiere decir que no
solo se trata de una simple cadena al estilo yyyy/MM/dd, sino que almacena hasta milisegundos y que es posible
trabajar con ellos.
Antes del jdk1.1 la clase java.util.Date tenía dos funciones adicionales a la que conocemos ahora, una de ellas era
la interpretación de datos que tenían que ver con fechas, como años, días, segundos, entre otros. La otra era el
formateo (la forma como se muestra) y parseo (convertir un String a java.util.Date). Pero debido a las dificultades
que presentaban estas funcionalidades a la hora de internacionalizar los programas, esos métodos ya está
obsoletos y la clase java.util.Calendar se encargó de esto; así que en este momento esta clase, sólo hace lo que se
mencionó al principio: "representa un instante de tiempo específico, con precisión de milisegundos"; más adelante
veremos como ampliar esta funcionalidad. Por ahora veamos las convenciones que sigue esta clase:
* El año "y" está representado por un entero igual a ("y" - 1900). Por ejemplo el año 2004 se representa como
104 (2004 - 1900).
* Los meses son representados por números entre 0 y 11, donde enero es 0 y diciembre es 11.
* Los días y minutos se representan de forma corriente. Entre 1 - 31 y 0 - 59 respectivamente.
* Las horas van entre 0 y 23, donde la medianoche es 0 y el medio día 12.
* Los segundos van entre 0 y 61. 61 solo ocurre cuando se agrega el segundo adicional para ajustar la diferencia
entre el reloj atómico y el tiempo de rotación de la tierra.
No sobra mencionar que los métodos para obtener el año, mes y día de esta clase ya están obsoletos y lo único
que hacen es llamar a la clase java.util.Calendar para que esta se encargue de hacerlo (una delegación).

java.sql.Date: Esta clase hereda de java.util.Date y es la representación de la fecha cuando trabajamos con JDBC
(Java DabaBase Connectivity), es decir, son los campos almacenados en una base de datos cuyo tipo es una fecha
que puede o no incluir la hora, aunque la clase java.sql.Date siempre lo hace. Al igual que su clase padre, tiene
una precisión de milisegundos, con la excepción que al mostrarla en la salida estándar con el formato por defecto
solo muestra el día, mes y año. Hay que anotar también que para campos que almacenen solamente horas existen
otras clases para manejarlos.

En resumen ambas clases, sólo se encargan de almacenar la cantidad de milisegundos que han pasado desde las
12 de la noche del primero de enero de 1970 en el meridiano de Greenwich. Aquí vienen dos puntos importantes:
a) Si la fecha que almacena cualquiera de las clases es menor a las 00:00:00 enero 1 de 1970 GMT, su valor el
milisegundos será negativo.
b) La fecha es susceptible a la zona horaria. Por ejemplo en Colombia los milisegundos no se empiezan a contar
desde enero 1 de 1970, sino a partir de las 19:00 de diciembre 31 de 1969. Esto es importante por que si
transportamos una fecha relativa de una zona a otra, podemos llegar a tener problemas al confiar en los
milisegundos que se tienen; además como la clase intenta representar el "Tiempo Universal Coordinado" (UTC)
suma 0.9 segundos cada año para ajustar la diferencia entre el reloj atómico y la velocidad de rotación de la tierra.
Esto se traduce en que muy dificilmente podemos basarnos en valores como 0 o 60000 para realizar validaciones,
pues esos milisegundos no son controlables cuando creamos la instancia de una fecha, peor aún, los milisegundos
no son ni siquiera iguales para la misma fecha en la misma zona horaria.
Ambas clases se pueden instanciar directamente mediante new(), pero la clase java.sql.Date necesita un
parámetro en el constructor: el tiempo en milisegundos, así que las siguientes instrucciones son válidas:

java.util.Date fechaActual = new java.util.Date(); //Fecha actual del sistema


java.sql.Date inicioLocal = new java.sql.Date(0); //Milisegundo cero

//también se puede crear una instancia de java.util.Date con parámetros iniciales


java.util.Date otraFecha = new java.util.Date(1000); //El primer segundo a partir del inicio

Prueba a imprimir cada uno de estos valores y fíjate en la diferencia de formatos entre java.sql.Date y
java.util.Date. Se puede pasar de java.sql.Date a java.util.Date de dos fomas, una de ellas es con una asignación
simple:

java.util.Date utilDate = null;


java.sql.Date sqlDate = new java.sql.Date(0);
utilDate = sqlDate;
/* aunque es java.util.Date,
si la imprimes tendrá el formato de java.sql.Date, recordemos que java.sql.Date hereda de
java.util.Date */
System.out.println(utilDate);

También se pueden tomar los milisegundos de java.sql.Date y pasarlos al constructor de java.util.Date:

java.util.Date utilDate = null;


java.sql.Date sqlDate = new java.sql.Date(0);
utilDate = new java.util.Date(sqlDate.getTime());
//esta vez se mostrará con el formato de java.util.Date
System.out.println(utilDate);

Para pasar de java.util.Date a java.sql.Date se deben tomar los milisegundos de la primera y pasarlos al
constructor de la segunda:

java.util.Date utilDate = new java.util.Date();


java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
//Con formato de java.sql.Date
System.out.println(sqlDate);

Para comparar fechas usamos el método compareTo() que internamente compara los milisegundos entre ellas
usando directamente los métodos getTime() de ambas clases.

java.util.Date utilDate = new java.util.Date();


java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
if (utilDate.compareTo(sqlDate) == 0){
System.out.println("IGUALES");
}else{
System.out.println("DIFERENTES");
}

O lo que es equivalente:

java.util.Date utilDate = new java.util.Date();


java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
if (utilDate.getTime() == sqlDate.getTime()){
System.out.println("IGUALES");
}else{
System.out.println("DIFERENTES");
}

2. Las clases Time y Timestamp.


Ambas clases pertenecen al API JDBC y son la encargadas de representar los campos de estos tipos en una base
de datos. Esto no quiere decir que no se puedan usar con otros fines. Al igual que java.sql.Date, son hijas
(heredan) de java.util.Date, es decir, su núcleo son los milisegundos.
La clase Time es un envoltorio de la clase java.util.Date para representar los datos que consisten de horas,
minutos, segundos y milisegundos, mientras Timestamp representa estos mísmos datos más un atributo con
nanosegundos, de acuerdo a las especificaciones del lenguaje SQL para campos de tipo TIMESTAMP.
Como ambas clases heredan del java.util.Date, es muy fácil pasar de un tipo de dato a otro; similar a la clase
java.sql.Date, tanto Time como Timestamp se pueden instanciar directamente y su constructor tiene como
parámetro el número de milisegundos; como es de imaginarse, cuando se muestra alguna de las clases mediante
su método toString() se ven los datos que intentan representar; La clase Time sólamente muestra la hora, minutos
y segundo, mientras timestamp agrega fracciones de segundo a la cadena.
Para convertir entre tipos de datos diferentes debemos usar los milisegundos de una clase y asignarlos a las
instancias de las otras, y como la clase java.util.Date es superclase de todas, a una instancia de esta podemos
asignar cualquiera de las otras, manteniendo los métodos de la clase asignada, es decir, si asignamos un Time a
una java.util.Date, al imprimir se verá el mismo formato de la clase Time.
Con este código:

java.util.Date utilDate = new java.util.Date(); //fecha actual


long lnMilisegundos = utilDate.getTime();
java.sql.Date sqlDate = new java.sql.Date(lnMilisegundos);
java.sql.Time sqlTime = new java.sql.Time(lnMilisegundos);
java.sql.Timestamp sqlTimestamp = new java.sql.Timestamp(lnMilisegundos);
System.out.println("util.Date: "+utilDate);
System.out.println("sql.Date: "+sqlDate);
System.out.println("sql.Time: "+sqlTime);
System.out.println("sql.Timestamp: "+sqlTimestamp);

Se obtiene la siguiente salida:

util.Date: Thu May 20 19:01:46 GMT-05:00 2004


sql.Date: 2004-05-20
sql.Time: 19:01:46
sql.Timestamp: 2004-05-20 19:01:46.593

Note que aún cuando todos los objetos tienen los mismos milisegundos el formato con el que se muestran
dependen de la clase que realmente los contiene. Es decir, no importa que a un objeto del tipo java.util.Date se le
asigne uno del tipo Time, al mostrar a través de la consola se invocará el método toString() de la clase time:

utilDate = sqlTime;
System.out.println("util.Date apuntando a sql.Time: ["+sqlTime+"]");
utilDate = sqlTimestamp;
System.out.println("util.Date apuntando a sql.Timestamp: ["+sqlTimestamp+"]");

Arroja:

util.Date apuntando a sql.Time: [19:29:47]


util.Date apuntando a sql.Timestamp: [2004-05-20 19:29:47.468]

Pero si en vez de solo apuntar, creamos nuevas instancias con los milisegundos los formatos con que se muestran
son los mismos. Note que lo verdaderamente importante ocurre cuando creamos la instancia de java.util.Date
usando los milisegundos del objeto sqlTime, pues aunque este último únicamente muestra horas, minutos y
segundos, siempre ha conservado todos los datos de la fecha con que se creó.

utilDate = new java.util.Date(sqlTime.getTime());


System.out.println("util.Date con milisegundos de sql.Time: ["+utilDate+"]");
utilDate = new java.util.Date(sqlTimestamp.getTime());
System.out.println("util.Date con milisegundos de sql.Timestamp: ["+utilDate+"]");

Fíjese en el formato de salida:

util.Date con milisegundos de sql.Time: [Thu May 20 19:54:42 GMT-05:00 2004]


util.Date con milisegundos de sql.Timestamp: [Thu May 20 19:54:42 GMT-05:00 2004]

Para finalizar esta primera entrega veamos el código para mostrar la diferencia entre dos fechas en horas, minutos
y segundos. Esta no es la mejor forma para hacerlo, pero cabe bien para mostrar de forma práctica todos los
conceptos anteriormente estudiados.
import java.util.HashMap;
import java.util.Map;
public class Prueba {
public static Map getDiferencia(java.util.Date fecha1, java.util.Date fecha2){
java.util.Date fechaMayor = null;
java.util.Date fechaMenor = null;
Map resultadoMap = new HashMap();

/* Verificamos cual es la mayor de las dos fechas, para no tener sorpresas al momento
* de realizar la resta.
*/
if (fecha1.compareTo(fecha2) > 0){
fechaMayor = fecha1;
fechaMenor = fecha2;
}else{
fechaMayor = fecha2;
fechaMenor = fecha1;
}

//los milisegundos
long diferenciaMils = fechaMayor.getTime() - fechaMenor.getTime();

//obtenemos los segundos


long segundos = diferenciaMils / 1000;

//obtenemos las horas


long horas = segundos / 3600;

//restamos las horas para continuar con minutos


segundos -= horas*3600;

//igual que el paso anterior


long minutos = segundos /60;
segundos -= minutos*60;

//ponemos los resultados en un mapa :-)


resultadoMap.put("horas",Long.toString(horas));
resultadoMap.put("minutos",Long.toString(minutos));
resultadoMap.put("segundos",Long.toString(segundos));
return resultadoMap;
}

public static void main(String[] args) {


//5:30:00 de Noviembre 10 - 1950 GMT-05:00
java.util.Date fecha1 = new java.util.Date(-604070999750L);

//6:45:20 de Noviembre 10 - 1950 GMT-05:00


java.util.Date fecha2 = new java.util.Date(-604066478813L);

//Luego vemos como obtuve esas fechas


System.out.println(getDiferencia(fecha1, fecha2));
}
}

DIFERENCIA ENTRE FECHAS


Fecha1: Fri Nov 10 05:30:00 GMT-05:00 1950
Fecha2: Fri Nov 10 06:45:21 GMT-05:00 1950
{segundos=20, horas=1, minutos=15}

Notas:
1. Existe un error de un segundo, lo cual no sucede cuando trabajamos con fechas posteriores a 1970, ¿Por qué?.
2. Este procedimiento funciona igual para todos los hijos de java.util.Date: java.sql.Date, java.util.Time y
java.util.Timestamp.
3. Todos los ejemplos los hemos hecho creando nuevas instancias de las clases. He omitido el traer información
desde una base de datos para no complicar el código; pero todo lo que hemos hecho debe funcionar igual de
ambas formas (con base de datos y usando constructores).
En la próxima entrega veremos como realizar operaciones completas entre fechas utilizando las clases Calendar y
GregorianCalendar.

También podría gustarte