¿Qué pasa con Java Date & Time API?

Muy a menudo encuentro comentarios negativos sobre Java Date y otras clases relacionadas con fecha-hora. Siendo un desarrollador de .NET, no puedo entender completamente (sin haberlos usado) lo que está realmente mal con ellos.

¿Alguien puede arrojar algo de luz sobre esto?

Ah, la clase Java Date . Tal vez uno de los mejores ejemplos de cómo no hacer algo en cualquier idioma, en cualquier lugar. ¿Dónde empiezo?

Leer el JavaDoc puede llevar a pensar que los desarrolladores realmente tienen algunas buenas ideas. Continúa sobre la diferencia entre UTC y GMT en longitud, a pesar del hecho de que la diferencia entre los dos es básicamente segundos intercalares (que ocurren muy raramente ).

Sin embargo, las decisiones de diseño realmente descartan cualquier idea de ser una API bien diseñada. Estos son algunos de los errores favoritos:

  • A pesar de haber sido diseñado en la última década del milenio, califica años como dos dígitos desde 1900. Hay literalmente millones de soluciones que superan los 1900+ (o 1900-) en el mundo de Java como resultado de esta decisión banal.
  • Los meses están indexados en cero, para atender el caso espectacularmente inusual de tener una serie de meses y no vivir con una matriz de trece elementos, el primero de los cuales contiene un null . Como resultado, tenemos 0..11 (y hoy es el mes 11 del año 109). Hay una cantidad similar de ++ y – en los meses para convertir a una cadena.
  • Ellos son mutables . Como resultado, cada vez que desee devolver una fecha (por ejemplo, como una estructura de instancia) debe devolver un clon de esa fecha en lugar del propio objeto de fecha (ya que de lo contrario, las personas pueden modificar su estructura).
  • El Calendar , diseñado para ‘arreglar’ esto, en realidad comete los mismos errores. Todavía son mutables.
  • Date representa un DateTime , pero para diferir a aquellos en SQL land, hay otra subclase java.sql.Date , que representa un solo día (aunque sin una zona horaria asociada).
  • No hay TimeZone asociadas a una Date , por lo que los intervalos (como un “día completo”) a menudo se representan como una medianoche a la medianoche (a menudo en una zona horaria arbitraria)

Finalmente, vale la pena señalar que los segundos intercalares generalmente se corrigen frente a un buen reloj del sistema que se actualiza con ntp en una hora (ver enlaces a continuación). La posibilidad de que un sistema siga en funcionamiento en la introducción de dos segundos intercalares (cada seis meses como mínimo, prácticamente cada pocos años) es bastante improbable, especialmente teniendo en cuenta el hecho de que tiene que volver a implementar versiones nuevas de su código de vez en cuando. . Incluso el uso de un lenguaje dynamic que regenera las clases o algo así como un motor de WAR contaminará el espacio de la clase y se quedará sin permgen eventualmente.

JSR 310 , que suplantó a las antiguas clases de fecha y hora con java.time en Java 8, se justifica en el JSR original de la siguiente manera:

2.5 ¿Qué necesidad de la comunidad Java será abordada por la especificación propuesta?

Actualmente, Java SE tiene dos API de fecha y hora separadas: java.util.Date y java.util.Calendar. Ambas API son consistentemente descritas como difíciles de usar por los desarrolladores de Java en weblogs y foros. Notablemente, ambos usan un índice cero durante meses, que es la causa de muchos errores. El calendario también ha sufrido muchos errores y problemas de rendimiento a lo largo de los años, principalmente debido a que almacena su estado de dos maneras diferentes internamente.

Un error clásico (4639407) impidió que ciertas fechas se crearan en un objeto de calendario. Se podría escribir una secuencia de código que podría crear una fecha en algunos años pero no en otros, lo que impediría que algunos usuarios ingresen sus fechas de nacimiento correctas. Esto fue causado por la clase Calendar que solo permitía una ganancia de horario de verano de una hora en verano, cuando históricamente era más de 2 horas en el momento de la segunda guerra mundial. Si bien este error ya está solucionado, si en algún momento en el futuro un país opta por introducir un aumento en el horario de verano de más de tres horas en verano, la clase Calendario volverá a romperse.

La API Java SE actual también sufre en entornos de subprocesos múltiples. Las clases inmutables son inherentemente seguras para subprocesos ya que su estado no puede cambiar. Sin embargo, tanto la fecha como el calendario son mutables, lo que requiere que los progtwigdores consideren clonar y enhebrar de forma explícita. Además, la falta de seguridad de hilos en DateTimeFormat no es ampliamente conocida, y ha sido la causa de muchos problemas difíciles de rastrear.

Además de los problemas con las clases que Java SE tiene para datetime, no tiene clases para modelar otros conceptos. Las fechas, horas, períodos e intervalos fuera de la zona horaria no tienen representación de clase en Java SE. Como resultado, los desarrolladores utilizan con frecuencia un int para representar una duración de tiempo, con javadoc especificando la unidad.

La falta de un modelo integral de fecha y hora también da como resultado que muchas operaciones comunes sean más complicadas de lo que deberían ser. Por ejemplo, calcular el número de días entre dos fechas es un problema particularmente difícil en la actualidad.

Esta JSR abordará el problema de un modelo completo de fecha y hora, que incluye fechas y horas (con y sin zonas horarias), duraciones y períodos de tiempo, intervalos, formateo y análisis sintáctico.

  • Las instancias de fecha son mutables , lo que casi siempre es inconveniente.
  • Ellos tienen una doble naturaleza. Representan una marca de tiempo y una fecha de calendario. Resulta que esto es problemático al hacer cálculos en fechas.
  • Las representaciones numéricas de los datos del calendario son contraintuitivas en muchos casos. Por ejemplo: getMonth() está basado en cero, getYear() está basado en 1900 (es decir, el año 2009 se representa como 109).
  • Faltan muchas funcionalidades que espera de una clase Date .

Siento por ti … como antiguo progtwigdor de .NET, hice las mismas preguntas, el tiempo API en .NET (intervalos de tiempo, sobrecarga del operador) es muy conveniente.

Primero, para crear una fecha específica, use una API obsoleta o:

 Calendar c = Calendar.getInstance(); c.set(2000, 31, 12) 

Para restar un día haces cosas malvadas como

 Date firstDate = ... Calendar c = Calendar.getInstance(); c.setTime(fistDate); c.add(Calendar.DATE,-1); Date dayAgo = c.getTime(); 

o peor

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

Para saber cuánto tiempo pasó entre dos fechas (en días / semanas / meses) … empeora aún más

Sin embargo, DateUtils de apache ( org.apache.commons.lang.time.DateUtils ) ofrece algunos métodos convenientes y me encontré usando solo ellos últimamente.

Como escribió Brabster, Joda Time también es una buena biblioteca externa, pero apache parece ser más “común” que otra cosa …

Encuentro utilizable la API de fecha de Java, para ser honesto. La mayoría de los problemas que he visto y oído se relacionan con la verbosidad, la necesidad de involucrar a varias clases para hacer algo útil ( Calendar , Date , DateFormat / SimpleDateFormat ) y la falta de getDayOfWeek() simples como getDayOfWeek() .

Joda Time es una API alternativa muy respetada en Java, y en la sección Por qué tiempo Joda da más argumentos sobre por qué es una alternativa viable que podría ser de interés.