Diferencias entre Date, DateTime y Calendar en Java 7

publicado por: Anonymous

Estoy usando Java 7 para desarrollar una aplicación para agendar conferencias.

He visto que hay varios tipos de datos para manejar las fechas.

Ejemplo:

private Date creationDate;

private DateTime creationDate;

private Calendar creationDate;

Mi pregunta es: ¿Cuál es la diferencia entre el tipo Calendar, Date y DateTime?

solución

De la documentación de java.util.Date (traducido):

La clase Date representa un instante específico en el tiempo, con precisión de milisegundos.

Mientras que java.util.Calendar (traducido, énfasis mía):

La clase Calendar es una clase abstracta que provee métodos para convertir entre un específico instante en el tiempo y un conjunto de campos de calendario como YEAR (año), MONTH (mes), DAY_OF_MONTH (día del mes), HOUR (hora) y así, y para manipular los campos del calendario, como obtener la fecha de la próxima semana.

El mayor problema acá en el diseño de la clase Date es que es mutable, cuando debió ser inmutable y la operación sobre fechas como aumentar (o disminuir) días, horas, segundos, años, etc, y generación de Dates debería ser a través de Calendar. Al menos esta es la forma en que suelo trabajar para evitar problemas al manejar los datos de Date. En Java 8 esto se resolvió al implementar un nuevo framework interno para manejo de fechas y horas llamado Java 8 Date and Time y las clases se pueden encontrar bajo el paquete java.time (tu pregunta es en base a Java 7, así que solo menciono esta parte de Java 8, no ahondaré más en este punto).

Para usar Calendar, te recomiendo siempre inicializarlo de la siguiente manera:

Calendar calendar = Calendar.getInstance();

Puesto que hay más de una implementación de Calendar, siendo la más conocida (y utilizada) GregorianCalendar, pero también están BuddhistCalendar y JapaneseImperialCalendar (al menos desde el código de Open JDK). El método Calendar#getInstance delega la creación del calendario al método createCalendar que para Java 8 está implementado de la siguiente manera (revisando el código fuente de HotSpot):

private static Calendar createCalendar(TimeZone zone,
                                       Locale aLocale)
{
    CalendarProvider provider =
        LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                             .getCalendarProvider();
    if (provider != null) {
        try {
            return provider.getInstance(zone, aLocale);
        } catch (IllegalArgumentException iae) {
            // fall back to the default instantiation
        }
    }

    Calendar cal = null;

    if (aLocale.hasExtensions()) {
        String caltype = aLocale.getUnicodeLocaleType("ca");
        if (caltype != null) {
            switch (caltype) {
            case "buddhist":
            cal = new BuddhistCalendar(zone, aLocale);
                break;
            case "japanese":
                cal = new JapaneseImperialCalendar(zone, aLocale);
                break;
            case "gregory":
                cal = new GregorianCalendar(zone, aLocale);
                break;
            }
        }
    }
    if (cal == null) {
        // If no known calendar type is explicitly specified,
        // perform the traditional way to create a Calendar:
        // create a BuddhistCalendar for th_TH locale,
        // a JapaneseImperialCalendar for ja_JP_JP locale, or
        // a GregorianCalendar for any other locales.
        // NOTE: The language, country and variant strings are interned.
        if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
            cal = new BuddhistCalendar(zone, aLocale);
        } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                   && aLocale.getCountry() == "JP") {
            cal = new JapaneseImperialCalendar(zone, aLocale);
        } else {
            cal = new GregorianCalendar(zone, aLocale);
        }
    }
    return cal;
}

Recomiendo siempre trabajar con Calendar porque se considera buena práctica trabajar con clases abstractas e interfaces en lo posible por sobre trabajar con la implementación directamente. Esto se cubre acá (en inglés): https://stackoverflow.com/q/383947/1065197

No conozco ninguna clase DateTime declarada en el JDK 7. Quizás te refieres a la clase org.joda.time.DateTime de la librería Joda Time (nombre curioso en español), la cual surge como una solución para evitar trabajar con Date que es mutable. DateTime es inmutable y las operaciones que realices sobre un DateTime en realidad crearán una nueva instancia de DateTime en lugar de modificar la instancia actual.


Si quieres saber cuál clase debes utilizar en tus proyectos, te daría las siguientes recomendaciones:

  • Para tus entidades, declara los campos de tipo Date (asegúrate que sean del paquete java.util).
  • Para realizar operaciones sobre Date como agregar o quitar tiempo, existen 2 opciones:
    • Crea un objeto de tipo Calendar, seteas su tiempo desde una instancia de Date vía Calendar#setTime, realizas las operaciones necesarias, y obtienes el Date de Calendar vía Calendar#getTime.
    • Procedimiento similar al descrito anteriormente, pero utilizando DateTime de Joda.
  • Si quieres representar una fecha y hora de manera textual, te recomiendo utilizar SimpleDateFormat#format(Date) (ojo, recibe Date y no Calendar) y evitar usar los métodos Date#getXyz. También podrías utilizar Calendar#get(Calendar.<campo>) pero el código sería muy verbose (no sé una traducción de esto).

¿Por qué no declarar directamente el uso de DateTime en los campos de tus entidades? Pues porque hay frameworks que no soportan la conversión directa a menos que implementes convertores particulares para ello. Algunos ejemplos: Hibernate1, JSF, Spring, etc.


1 Hibernate 5 ahora ofrece soporte para la librería Date Time de Java 8. Supongo que los frameworks poco a poco irán yendo por ese camino también en algún momento.

Respondido por: user227

Leave a Reply

Your email address will not be published. Required fields are marked *