Fecha Java vs Calendario


364

¿Podría alguien aconsejar sobre las "mejores prácticas" actuales Datey sus Calendartipos?

Al escribir código nuevo, es lo mejor para favorecer siempre Calendarmás Date, o hay circunstancias en las que Datees el tipo de datos más apropiado?



2
Para su información, las clases de fecha y hora viejas problemáticas tales como java.util.Date, java.util.Calendary java.text.SimpleDateFormatahora están legado, suplantados por los java.time clases. Gran parte de la funcionalidad java.time se transfiere a Java 6 y Java 7 en el proyecto ThreeTen-Backport . Más adaptado para Android anterior en el proyecto ThreeTenABP . Ver Cómo utilizar ThreeTenABP ... .
Basil Bourque

2
Para su información, el proyecto Joda-Time (mencionado en otro comentario) ahora está en modo de mantenimiento , y el equipo aconseja migrar a las clases java.time . Ver Tutorial de Oracle .
Basil Bourque

Respuestas:


377

La fecha es una clase más simple y está principalmente allí por razones de compatibilidad con versiones anteriores. Si necesita establecer fechas particulares o hacer aritmética de fechas, use un calendario. Los calendarios también manejan la localización. Las funciones de manipulación de fecha anteriores de Fecha han quedado en desuso.

Personalmente, tiendo a usar el tiempo en milisegundos como largo (o Largo, según corresponda) o Calendario cuando hay una opción.

Tanto la fecha como el calendario son mutables, lo que tiende a presentar problemas cuando se usa en una API.


55
Para su información, las antiguas clases de fecha y hora terriblemente problemáticas como java.util.Date, java.util.Calendary java.text.SimpleDateFormatahora son heredadas , suplantadas por las clases java.time integradas en Java 8 y posteriores. Ver Tutorial de Oracle .
Basil Bourque

67

La mejor manera de obtener un código nuevo (si su política permite código de terceros) es usar la biblioteca Joda Time .

Ambos, Fecha y Calendario , tienen tantos problemas de diseño que ninguna de las dos son buenas soluciones para el nuevo código.


77
Secundo la sugerencia de usar el tiempo joda. Es más fácil de usar y comprender, y ofrece mucha más funcionalidad que puede usar.
Jeroen van Bergen

30
Para una discusión sobre si usar Joda Time o seguir con las clases estándar de JDK, consulte stackoverflow.com/questions/589870/…
Jonik

3
No sé si merece votos negativos, pero no responde la pregunta. Podría ser mejor como comentario.
IcedDante

77
Debido a que la pregunta era sobre el uso de Fecha y Calendario, no el uso de una biblioteca de terceros que agrega un solo riesgo de dependencia del proveedor a un proyecto.
Arquímedes Trajano

3
Esta fue la "mejor manera" hasta que el paquete java.time estuvo disponible con Java 8.
DaBlick

58
  • Datey Calendarson realmente el mismo concepto fundamental (ambos representan un instante en el tiempo y son envoltorios alrededor de un longvalor subyacente ).

  • Uno podría argumentar que en Calendarrealidad está aún más roto de lo queDate está, ya que parece ofrecer hechos concretos sobre cosas como el día de la semana y la hora del día, mientras que si cambia su timeZonepropiedad, ¡el concreto se convierte en manjar blanco! Ninguno de los dos objetos es realmente útil como almacén de año-mes-día o hora del día por este motivo.

  • Úselo Calendarsolo como una calculadora que, cuando se da Datey los TimeZoneobjetos, harán los cálculos por usted. Evite su uso para escribir propiedades en una aplicación.

  • Use SimpleDateFormatjunto con TimeZoney Datepara generar cadenas de visualización.

  • Si se siente aventurero, use Joda-Time, aunque en mi humilde opinión es innecesariamente complicado y pronto será reemplazado por la API de fecha JSR-310 en cualquier caso.

  • He respondido antes que no es difícil rodar su propia YearMonthDayclase, que utiliza Calendardebajo del capó para los cálculos de fechas. Me rechazaron la sugerencia, pero sigo creyendo que es válida porque Joda-Time (y JSR-310 ) son realmente demasiado complicados para la mayoría de los casos de uso.


1
¿Hay un marco de tiempo para JSR310? Iba a estar en Java 7, pero creo que ahora no es el caso.
Brian Agnew

@Brian - ¡ciertamente se ha vuelto muy silencioso en esa lista de correo!
oxbow_lakes

Solo verificando, se ha desactivado, lo que significa que no han publicado un borrador de hito en 18 meses :-(
Brian Agnew

Más reciente comentario sobre la lista de distribución es de julio y por Stephen, por lo que el proyecto está probablemente todavía apremia
oxbow_lakes

Convenido. Si sabe cómo usar Date de manera segura como un objeto inmutable y Calendar para manipular Dates, la mayoría de las personas deberían estar a salvo. Tenga cuidado al usar SimpleDateFormat en código multiproceso.
cwash

25

La fecha es mejor para almacenar un objeto de fecha. Es el persistente, el serializado ...

El calendario es el mejor para manipular fechas.

Nota: a veces también preferimos java.lang. Long over Date, porque Date es mutable y, por lo tanto, no es seguro para subprocesos. En un objeto Date, use setTime () y getTime () para cambiar entre los dos. Por ejemplo, una Fecha constante en la aplicación (ejemplos: el cero 01/01/1970 o un END_OF_TIME aplicativo que establezca en 2099/12/31; esos son muy útiles para reemplazar los valores nulos como hora de inicio y hora de finalización, especialmente cuando los persiste en la base de datos, ya que SQL es tan peculiar con los nulos).


Supongo que te estás tomando lo inmutablejava.lang.Long
pjp

17

Generalmente uso Fecha si es posible. Aunque es mutable, los mutadores en realidad están en desuso. Al final, básicamente envuelve un largo que representaría la fecha / hora. Por el contrario, usaría Calendarios si tuviera que manipular los valores.

Puede pensarlo de esta manera: solo usa StringBuffer solo cuando necesita tener Strings que puede manipular fácilmente y luego convertirlos en Strings usando el método toString (). De la misma manera, solo uso el Calendario si necesito manipular datos temporales.

Para la mejor práctica, tiendo a usar objetos inmutables tanto como sea posible fuera del modelo de dominio . Reduce significativamente las posibilidades de cualquier efecto secundario y el compilador lo hace por usted, en lugar de una prueba JUnit. Utiliza esta técnica creando campos finales privados en tu clase.

Y volviendo a la analogía de StringBuffer. Aquí hay un código que le muestra cómo convertir entre Calendario y Fecha

String s = "someString"; // immutable string
StringBuffer buf = new StringBuffer(s); // mutable "string" via StringBuffer
buf.append("x");
assertEquals("someStringx", buf.toString()); // convert to immutable String

// immutable date with hard coded format.  If you are hard
// coding the format, best practice is to hard code the locale
// of the format string, otherwise people in some parts of Europe
// are going to be mad at you.
Date date =     new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2001-01-02");

// Convert Date to a Calendar
Calendar cal = Calendar.getInstance();
cal.setTime(date);

// mutate the value
cal.add(Calendar.YEAR, 1);

// convert back to Date
Date newDate = cal.getTime();

// 
assertEquals(new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2002-01-02"), newDate);

Sí, los objetos inmutables tienen sentido para el trabajo de fecha y hora. Las clases java.time que suplantaron Date/ Calendarusan el patrón de objetos inmutables.
Basil Bourque

Eso puede ser cierto, pero no en 2010.
Archimedes Trajano

Si. Pero hay miles de personas que están leyendo esta página ahora , más de 150.000 hasta el momento. Mi comentario es una nota para ellos, no una crítica de usted.
Basil Bourque

Lo sé, por eso voté por la otra respuesta. Sin embargo, todavía hay algunas personas que necesitan sufrir con los JDK más antiguos que también necesitan la respuesta anterior.
Arquímedes Trajano

1
En realidad, para Java 6 y 7, tenemos el proyecto ThreeTen-Backport . Esto trae la mayor parte de la funcionalidad java.time con prácticamente la misma API. Por lo tanto, no hay necesidad de usar esas terribles clases de fecha y hora heredadas.
Basil Bourque

15

Dates debe usarse como puntos inmutables en el tiempo; Calendars son mutables, y se pueden pasar y modificar si necesita colaborar con otras clases para llegar a una fecha final. Considérelos análogos a StringyStringBuilder comprenderá cómo considero que deberían usarse.

(Y sí, sé que Date no es técnicamente inmutable, pero la intención es que no sea mutable, y si nada llama a los métodos obsoletos, entonces es así).


Sí, los objetos inmutables tienen sentido para el trabajo de fecha y hora. Las clases java.time que suplantaron Date/ Calendarusan el patrón de objetos inmutables. Específicamente, Instantreemplaza java.util.Datey ZonedDateTimereemplaza Calendar/ GregorianCalendar.
Basil Bourque

15

tl; dr

aconsejar la "mejor práctica" actual en torno Date yCalendar

es la mejor forma de favorecer siempre Calendarpor encimaDate

Evite estas clases heredadas por completo. Use java.time clases lugar.

  • Por un momento en UTC , useInstant
    (el equivalente moderno deDate )
  • Por un momento en una zona horaria particular , use (el equivalente moderno deZonedDateTime
    GregorianCalendar )
  • Por un momento en un desplazamiento particular desde UTC , useOffsetDateTime
    (sin equivalente en clases heredadas)
  • Para una fecha y hora (no un momento) con zona horaria o desplazamiento desconocidos, use (sin equivalente en las clases heredadas)LocalDateTime

Tabla de todos los tipos de fecha y hora en Java, tanto modernos como heredados

Detalles

La respuesta de Ortomala Lokni es correcta al sugerir el uso de las clases modernas de java.time en lugar de las antiguas y problemáticas clases de fecha y hora heredadas ( Date,Calendar , etc.). Pero esa respuesta sugiere la clase incorrecta como equivalente (ver mi comentario sobre esa respuesta).

Usando java.time

Las clases java.time son una gran mejora con respecto a las clases heredadas de fecha y hora, la diferencia de día y noche. Las viejas clases están mal diseñadas, son confusas y problemáticas. Debe evitar las clases antiguas siempre que sea posible. Pero cuando necesite convertir a / de lo antiguo / nuevo, puede hacerlo llamando a nuevos métodos add to the old clases .

Para obtener más información sobre la conversión, vea mi respuesta y diagrama ingenioso a otra pregunta, Convertir java.util.Date a qué tipo de "java.time"?.

Search Stack Overflow ofrece muchos cientos de preguntas y respuestas de ejemplo sobre el uso de java.time. Pero aquí hay una sinopsis rápida.

Instant

Obtenga el momento actual con un Instant. La Instantclase representa un momento en la línea de tiempo en UTC con una resolución de nanosegundos (hasta nueve (9) dígitos de una fracción decimal).

Instant instant = Instant.now();

ZonedDateTime

Para ver ese mismo momento simultáneo a través de la lente del reloj de pared de una región en particular , aplique una zona horaria ( ZoneId) para obtener a ZonedDateTime.

Zona horaria

Especificar un nombre de zona horaria correcta en el formato de continent/region, por ejemplo America/Montreal, Africa/Casablancao Pacific/Auckland. Nunca use el 3-4 abreviatura de letras tales como ESTo IST, ya que son no verdaderas zonas de tiempo, no estandarizados, y ni siquiera único (!).

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone();

Compensar

Una zona horaria es el historial de cambios de una región en su desplazamiento desde UTC . Pero a veces solo se le da un desplazamiento sin la zona completa. En ese caso, usa la OffsetDateTimeclase.

ZoneOffset offset = ZoneOffset.parse( "+05:30" );
OffsetDateTime odt = instant.atOffset( offset );

El uso de una zona horaria es preferible al uso de un mero desplazamiento.

LocalDateTime

El "Local" en las Local…clases significa cualquier localidad, no una localidad particular. Entonces el nombre puede ser contra-intuitivo.

LocalDateTime, LocalDatey LocalTimecarecen deliberadamente de información sobre desplazamiento o zona horaria. Así que ellos no representan momentos reales, que son no los puntos de la línea de tiempo. En caso de duda o confusión, use en ZonedDateTimelugar de LocalDateTime. Buscar Stack Overflow para mucha más discusión.

Instrumentos de cuerda

No combine objetos de fecha y hora con cadenas que representen su valor. Puede analizar una cadena para obtener un objeto de fecha y hora, y puede generar una cadena a partir de un objeto de fecha y hora. Pero la cadena nunca es la fecha-hora misma.

Aprenda sobre los formatos estándar ISO 8601 , utilizados por defecto en las clases java.time.


Sobre java.time

El marco java.time está integrado en Java 8 y versiones posteriores. Estas clases suplantar la vieja problemáticos heredados clases de fecha y hora como java.util.Date, Calendar, y SimpleDateFormat.

El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .

Para obtener más información, consulte el Tutorial de Oracle . Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310 .

Con un controlador JDBC compatible con JDBC 4.2 o posterior, puede intercambiar java.time objetos directamente con su base de datos. No necesita cadenas ni clases java.sql. *.

¿Dónde obtener las clases java.time?

  • Java SE 8 , Java SE 9 y posterior
    • Incorporado.
    • Parte de la API Java estándar con una implementación integrada.
    • Java 9 agrega algunas características menores y correcciones.
  • Java SE 6 y Java SE 7
    • Gran parte de la funcionalidad java.time se transfiere a Java 6 y 7 en ThreeTen-Backport .
  • Androide
    • Versiones posteriores de las implementaciones de paquetes de Android de las clases java.time.
    • Para principios de Android, el ThreeTenABP proyecto se adapta ThreeTen-Backport (mencionado anteriormente). Ver Cómo utilizar ThreeTenABP ... .

Tabla de qué biblioteca java.time usar con qué versión de Java o Android

El proyecto ThreeTen-Extra extiende java.time con clases adicionales. Este proyecto es un campo de pruebas para posibles adiciones futuras a java.time. Usted puede encontrar algunas clases útiles aquí, como Interval, YearWeek, YearQuarter, y más .


10

Con Java 8, se debe usar el nuevo paquete java.time .

Los objetos son inmutables, se tienen en cuenta las zonas horarias y el ahorro de luz diurna.

Puede crear un ZonedDateTimeobjeto a partir de un java.util.Dateobjeto antiguo como este:

    Date date = new Date();
    ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault());

Es bueno sugerir las clases java.time. Pero es malo sugerir LocalDateTime. Esa clase pierde deliberadamente cualquier información sobre offset-from-UTC y zona horaria. Por lo tanto, esa clase no es equivalente como Dateen UTC y Calendartiene una zona horaria asignada. Vea mi respuesta y diagrama ingenioso a otra pregunta, Convertir java.util.Date a qué tipo de "java.time"? .
Basil Bourque

9

Siempre abogo por Joda-time . Este es el por qué.

  1. La API es consistente e intuitiva. A diferencia de las API java.util.Date/Calendar
  2. no sufre problemas de subprocesos, a diferencia de java.text.SimpleDateFormat, etc. (He visto numerosos problemas de clientes relacionados con no darse cuenta de que el formato estándar de fecha / hora no es seguro para subprocesos)
  3. es la base de las nuevas API de fecha / hora de Java ( JSR310 , programadas para Java 8. Por lo tanto, utilizará API que se convertirán en las principales API de Java.

EDITAR: las clases de fecha / hora de Java introducidas con Java 8 ahora son la solución preferida, si puede migrar a Java 8


3
La última vez que miré, JODA y JSR-310 se veían muy diferentes, incluso si ambos fueron escritos por Stephen Colebourne. Dicho esto, JODA que introduciría a la complejidad de los problemas de fecha y hora que JSR-310 también soluciona
oxbow_lakes

2
Debido a que la pregunta era sobre el uso de Fecha y Calendario, no el uso de una biblioteca de terceros que agrega un solo riesgo de dependencia del proveedor a un proyecto.
Arquímedes Trajano

2
Mantengo que la mejor práctica es simplemente no usar esas clases
Brian Agnew

3
Dados los problemas conocidos con las clases java.util.Date y Calendar, sugerir Joda-Time (o JSR 310) me parece apropiado y responsable. No estamos hablando de una cuestión de gustos o estilo estético. Si alguien preguntara si deberían tomar el automóvil rojo o el plateado, y yo supiera que el automóvil rojo tenía una rueda pinchada y el automóvil plateado tenía un radiador roto, ¿debería elegir un automóvil o sugerirle que llame a un taxi? La respuesta a esa pregunta debería parecer obvia hoy en día, ya que incluso Sun / Oracle decidió dejar atrás esos junkers y comprar un auto nuevo: JSR 310: API de fecha y hora.
Basil Bourque

1
Para su información, el proyecto Joda-Time ahora está en modo de mantenimiento , y aconseja la migración a las clases java.time . Ver Tutorial de Oracle .
Basil Bourque

8

Un poco tarde en la fiesta, pero Java tiene una nueva API de fecha y hora en JDK 8. Es posible que desee actualizar su versión de JDK y adoptar el estándar. No más calendario / fecha desordenada, no más frascos de terceros.


1

La fecha debe volver a desarrollarse. En lugar de ser un número entero largo, debe contener año, mes, fecha, hora, minuto, segundo, como campos separados. Incluso podría ser bueno almacenar el calendario y la zona horaria a la que está asociada esta fecha.

En nuestra conversación natural, si establecemos una cita el 1 de noviembre de 2013 a las 1 p.m., hora de Nueva York, esta es una fecha y hora. NO es un calendario. Por lo tanto, también deberíamos poder conversar así en Java.

Cuando la fecha se almacena como un entero largo (de milisegundos desde el 1 de enero de 1970 o algo así), el cálculo de su fecha actual depende del calendario. Los diferentes calendarios darán una fecha diferente. Esto proviene de la perspectiva de dar un tiempo absoluto (por ejemplo, 1 billón de segundos después de Big Bang). Pero a menudo también necesitamos una forma conveniente de conversación, como un objeto que encapsula año, mes, etc.

Me pregunto si hay nuevos avances en Java para conciliar estos 2 objetivos. Tal vez mi conocimiento de Java es demasiado viejo.


El hecho de que pueda almacenar el mismo instante en el tiempo, pero informar diferentes horas / minutos / día / semana / año / año basado en diferentes sistemas de calendario, es una fortaleza, no una debilidad. Refleja la realidad (compleja).
ThrawnCA

De hecho, Datese ha vuelto a desarrollar; reemplazado por la java.time.Instantclase. Y Calendar/ GregorianCalendarfue reemplazado por java.time.ZonedDateTimeclase.
Basil Bourque


0

Uso Calendar cuando necesito algunas operaciones específicas durante las fechas, como moverme en el tiempo, pero Date me parece útil cuando necesitas formatear la fecha para adaptar tus necesidades, recientemente descubrí que Locale tiene muchas operaciones y métodos útiles. Estoy usando Locale ahora mismo!


Para su información, la problemática Calendary Datelas clases fueron reemplazados hace años por los java.time clases. No hay necesidad de usar Dateo Calendar. Y Localeno tiene nada que ver con el significado de los objetos de fecha y hora. A Localesolo se utiliza para especificar el lenguaje humano y las normas culturales que se utilizarán en la localización mientras se genera texto para representar el valor de un objeto de fecha y hora.
Basil Bourque
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.