Cronología de la principal catástrofe de las APIs Java: java.util.Date
Con el motivo de la adición del JSR 310, "Date and Time API", a la lista de características oficiales que estarán soportadas en Java 8, InfoQ ha publicado un pequeño resumen de la historia de lo que probablemente sea la metedura de pata más grande de los APIs estándar Java: java.util.Date. Os dejo aquí un resumen de esa historia, completando algunos aspectos.
Todo empezó en 1995 con la primera versión de Java, 1.0. java.util.Date pasó a formar parte del paquete que, junto con java.lang, pueden considerarse el conjunto de clases más core de todo el API estándar. La elección de la representación temporal, un campo numérico que contenía tanto información acerca del día como de la hora, no fue muy acertada, sobre todo por lo complicada que es de internacionalizar. Además, el API tenía un comportamiento bastante confuso. Los meses y las horas comienzan a contar en "0", pero los días comienzan a contar en "1". Y los años comienzan a contar en "1900". Eso a pesar de que el campo encapsulado por java.util.Date cuenta el offset en milisegundos a partir del 1 de Enero, 1970 00:00:00.000 GMT, por lo que si representamos fechas anteriores a este año se representarán por un valor negativo.
Para terminar de rematar la faena, los objetos java.util.Date son mutables, por lo tanto propensos a problemas de multithreading y en estos escenarios a menudo es necesario estar haciendo copias de ellos todo el tiempo.
En 1997 con Java 1.1 se añadió soporte para SQL. Y con este soporte se añadió la clase java.sql.Date, que hereda de java.util.Date, pero a pesar de que un java.sql.Date es un java.util.Date la clase tiene un propósito diferente: sólo representa fechas, no horas, minutos o seguntos. Por lo que pone a cero las horas, minutos, segundos y milisegundos de java.util.Date. Y para incrementar todavía más la confusión, hay un segundo wrapper para java.util.Date que también hereda de él, java.sql.Timestamp, que si que tiene horas, minutos, segundos y nanosegundos (no milisegundos). Obvio.
En 1998 IBM contribuyó una clase que pretendía reemplazar a java.util.Date: java.util.Calendar. Tenía un soporte de internacionalización más aceptable, y era muy flexible. Demasiado. Tanto que incluso hacer tareas sencillas con ella puede ser bastante complejo.
Este es el contexto que llevó a Stephen Colebourne a publicar en 2005 su librería alternativa para trabajar con fechas en Java: Joda-time. La librería era una mejora significativa respecto a las API estándar, y pronto ganó popularidad. Pero no dejaba de ser una librería externa que proporcionaba una funcionalidad que debía formar parte del core de la plataforma. Por ello en enero de 2007 se crea un JSR para, inspirándose en Joda-time, estandarizar esta librería e incorporarla a la plataforma.
Debería haber sido parte de Java 7, pero el derrumbamiento de Sun en sus últimos años de existencia, junto con las circunstancias en general, conspiraron para que no estuviese lista. Ahora, por fin, en 2012 ha sido añadida como característica que estará presente en Java 8, y acaba de comenzar el trabajo de integración en OpenJDK. En octubre de 2013 se liberará Java 8, y por fin, casi 20 años después, tendremos un API decente para trabajar con fechas.
Reader Comments (18)
Coincidiréis conmigo en que esperar casi 20 años para tener una librería decente de fechas!!! (no de manejo de satélites y cálculo de órbitas y/o robótica de última generación, no, manejo de fechas!!!!!) en un lenguaje con las aspiraciones y el prestigio de Java es un exceso absoluto.
Lo peor ahora es que java.sql.Date va a seguir ahí, y hay muchas librerías que lo usan. Y mucha gente que no se va a molestar en aprender lo nuevo. Vamos, que no nos quitamos el muerto de encima, al menos no completamente.
Tampoco es tan terrible trabajar con Calendars y Dates ... una vez que se aprende como hacerlo ya está.
Para mi una de las peores cosas de java.util.Date y java.sql.Date es que una herede de la otra, se llamen igual, encima el package es parecido y están en el mismo jar (rt.jar).
La cantidad de veces que tuve un java.sql.Date en lugar del otro y que por heredar todo compila y funciona pero no como debe!!
Uno de lo errores mas grandes tener una clase que hereda de otra y que se llamen igual, y en el core......
De acuerdo con Abraham y con Martín, lo veo bien como cambio, pero es un cambio.... Calendar, una vez que se aprede, es manejable.
Pero bueno veremos a ver qué nos aporta, la verdad es que se lucieron en su momento con esta librería.
Programando c++ "a pelo" con la STL y las boost, ya nos hubiera gustado tener un API del estilo de Calendar para manejar las fechas.
Desde la comodidad de Java, nos olvidamos de que muchos lenguajes aun no tienen nada parecido a la libreria standar de java.
Teniendo en cuenta la cantidad de características pospuestas en las últimas versiones de Java no me extrañaría que esta también se acabe posponiendo para Java 9 cuando los tiempos a los chicos de Oracle no les cuadren con la cantidad de trabajo, y teniendo en cuenta que JODA ya existe y existe Date y Calendar, tampoco sería tan urgente que estuviese en Java 8 si se ven obligados a nuevos retrasos...
Este es Oracle, grande por fuera y corto de miras por dentro. Hudson, Open Office, My SQL, retrasos continuos en características Java... ¿qué será lo siguiente?
De verdad yo no veo donde está el "terrible" problema, Date fue una cagada de ¡¡¡¡¡¡¡Java 1.0!!!!!!!! que si mal no recuerdo se "solucionó" en la 1.1, con las prisas y la visión EEUU-céntrica del mundo de los primeros programadores del SDK de Java hicieron un objeto fecha pensado para Carolina del Sur.
Solución: fuera métodos (deprecated) y lo dejamos como un simple contenedor del entero timestamp y ya está, pero que esto se hizo en la 1.1, Java tiene cientos y cientos de métodos deprecated, la propia API de Android también tiene muchos y es una API mucho más joven.
Respecto a java.sql.Date NO es verdad "por lo que pone a cero las horas, minutos, segundos y milisegundos de java.util.Date"
"To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date instance must be 'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated."
http://docs.oracle.com/javase/1.4.2/docs/api/java/sql/Date.html
Es decir que lo hagas tú para que no te sorprendas de que el valor que obtienes de la base de datos es diferente al que metiste, no que lo haga java.sql.Date, desde luego no lo hace java.sql.Date, que de nuevo no es más que un contenedor con entero long.
http://javasourcecode.org/html/open-source/jdk/jdk-6u23/java.sql/Date.java.html
" Los meses y las horas comienzan a contar en "0", pero los días comienzan a contar en "1"" pues ciertamente es algo un poco raro que los días empiecen en 1, pero que empiece todo en cero a estas alturas de la vida me parece lo más normal del mundo.
En resumen, las clases Date para mi son de enorme utilidad porque me dan un significado semántico de fecha aunque para lo único que verdaderamente valen es para alojar un long.
La única "queja" que tengo del sistema de fechas de Java es que java.util.Calendar no es muy amigable porque ciertamente es un poco peligrosilla de usar, pero vamos tampoco es uranio radiactivo.
Más interés por la modularidad y más Java-FX Mobile y menos joda-time, que si Windows Phone prospera y BlackBerry se mantiene algunos nos vemos programando aplicaciones móviles con JavaScript en un WebKit embebido depurando con mensajes por consola en pleno 2012.
Teniendo en cuenta que la implementación actual del JSR 310 tiene 257 clases, espero que no se cumpla el refrán: "Entre todas la mataron, y ella sola se murió" :D
<<java.util.Date son mutables, por lo tanto propensos a problemas de multithreading y en estos escenarios a menudo es necesario estar haciendo copias de ellos todo el tiempo.>> Pues en escenarios concurrentes, es mas eficiente hacer copias de objetos que protegerlos con mutex. Si fueran objetos diseñados para soportar el acceso simultaneo de muchos threads con bloqueos, no solo se perjudica la ejecucion concurrente sino también la ejecucion en un solo hilo innecesariamente.
la implementación actual del JSR 310 tiene 257 clases
Mirando al proyecto de Github
https://github.com/ThreeTen/threeten/tree/master/src/main/java
veo algo como 65 clases, y la mayoria no utilisa un programador.
Me refiero a clases, no a archivos .java
Si descargas el proyecto, verás que tiene esas 257 .class
Con respecto a @jmarranz, Calendar ofrece operaciones sobre días, meses y años, que no ofrece Date. Esa es la ventaja que tiene, es un complemento interesante a tener en cuenta.
Yo divido el problema en dos partes: una, integración de objeto Date con bases de datos (algo que viene pasando con las integraciones de base de datos y la necesidad de entender dos idiomas diferentes y necesitar una clase intermedia), y dos, la ilegibilidad, a priori, o dificultad de aprendizaje de Date, que se vió compensada con el objeto Calendar.
Yo no veo una necesidad de cambio en este sentido, desde mi punto de vista. Si hay que medir esfuerzos, escogería otras características diferentes, pero bueno, es una opinión a bote pronto.
@superoptimo
Precisamente porque en trabajo concurrente es mejor (mas eficiente en procesador y menos propenso a fallos) tener objetos inmutables que usar mutex, el hecho de que Date sea mutable es una puñeta!
Si son inmutables, no hace falta hacerles copias ni protegerlos con mutex, porque el valor del objeto jamas cambiara ;)
Esperemos que respete compatibilidad hacia atrás, a ver quién es el valiente que se pone a hacer refactoring.
Grandes peleas ha dado este tema, al menos sólo eran dialécticas
Sobre la inmutabilidad de un objeto, y que por ello sea "automáticamente" thread-safe, este artículo arroja bastante claridad, y muestra que expresiones habituales no son necesariamente ciertas, por más que se repitan.
http://invalidcodeexception.com/do-immutability-really-means-thread-safety/
¿ Alguno ha serializado un calendar? 900 bytes cuando con un long es suficente.