Fusionar java.util.date con java.sql.Time

Tengo una clase extensa de conversión de FECHA-HORA, pero me encontré con un escenario que no puedo resolver:

Tengo un java.util.date: martes 10 de mayo 00:00:00 BST 2011
Tengo un java.sql.time: 03:58:44

Necesito crear un java.util.date: martes 10 de mayo 03:58:44 BST 2011

El único enfoque que se me ocurrió es:

public static Date getDate(Date date, Time time) {
    Calendar calendar=Calendar.getInstance();
    calendar.set(date.getYear(), date.getMonth(), date.getDay(), time.getHours(), time.getMinutes(), time.getSeconds());
    return calendar.getTime();
}

Código totalmente obsoleto y no funciona: java.lang.IllegalArgumentException en java.sql.Time.getYear (fuente desconocida)

¿Alguna idea?

preguntado el 10 de mayo de 11 a las 13:05

Si obtuviste esa excepción en ese código, entonces en realidad pasaste un Time instancia en el primer parámetro! -

joda-time es siempre el mejor enfoque para trabajar con fechas en java joda-time.sourceforge.net -

En una nota parcialmente relacionada: mientras que el java.util.Date La API está muy mal construida y hace mucho que debería haber sido reemplazada por una sana (como Hora de Joda), el java.sql.Date y java.sql.Time "extensión" es aún peor: ellos en no sigas el Principio de sustitución de Liskov y para empeorar las cosas java.sql.Date incluso tiene el mismo nombre simple que su clase base. -

Estoy de acuerdo, tuve que hacer una clase de conversión optimizada que tenga todo lo que necesito y una que me haga SENSE ... java.util.date es una molestia ... pero en este momento solo necesito una solución simple para este escenario. -

7 Respuestas

java.sql.Time es solo un contenedor sobre java.util.Date. Puede usarlo como si agregara dos objetos java.util.Date.

Por ejemplo, establezca Calendar en java.sql.Time:

calendar.setTime(time);

Ahora extraiga los campos de hora / minuto / segundos, es decir:

calendar.get(Calendar.HOUR);

A continuación, configure el Calendario en el objeto java.util.Date y agregue estos tres campos a su hora, es decir:

calendar.add(Calendar.HOUR, hour);

Y recupera la fecha:

calendar.getTime();

contestado el 10 de mayo de 11 a las 17:05

Solo un comentario: debemos usar HOUR_OF_DAY para respetar el formato de 24 horas. - marcolopes

La forma más fácil sería simplemente sumar los milisegundos para crear una nueva fecha, ala

public static Date getDate(Date date, Time time) {
    return new Date(date.getTime() + time.getTime())
}

contestado el 10 de mayo de 11 a las 17:05

Funciona, pero obtengo una hora menos ... Martes 10 de mayo 00:00:00 BST 2011 & 03:58:44 = Martes 10 de mayo 02:58:44 BST 2011 - marcolopes

La solución de vickirk no fue tan mala, pero tiene problemas de zona horaria, lo que da como resultado una hora menos que observó.

Supongo que BST significa British Summer Time, que es GMT +0100. Ahora, java.util.Date y sus descendientes trabajan internamente con números de milisegundos desde la medianoche del 01 de enero de 1970. GMT. La zona horaria no se tiene en cuenta hasta que se cadena la fecha / hora con toString(). Y usan su zona horaria local para eso, que aparentemente es BST. Eso significa que lo que realmente se almacena en estos objetos es

java.util.date: lunes de mayo 09 23: 00: 00 GMT 2011
java.sql.time: 02: 58: 44 GMT

Cuando agrega los valores internos (que son recuperados por getTime()) como sugirió vickirk, obtienes una fecha que contiene
Martes mayo 10 01: 58: 44 GMT 2011, que luego resulta en
Martes mayo 10 02: 58: 44 BST 2011 sobre encadenamiento.

Entonces, la explicación para una hora menos es que el desplazamiento de la zona horaria se aplica dos veces, cuando se encadenaron los valores por separado, mientras que se aplica solo una vez después de la adición, porque ahora solo se encadena una vez. O, desde otro punto de vista, sumando el valor interno de la punto en el tiempo 03:58:44 BST es equivalente a agregar un espacio de tiempo de 2h 58m 44s.

Así que para conseguir un tiempo lapso de 3h 58m 44s codificado en un java.sql.Time, debe compensar el desplazamiento de zona horaria manualmente. Para ello, analiza la cadena de tiempo "00:00:00" con java.sql.Time, lo que dará como resultado un valor interno de -3600000 que equivale al 31 de diciembre de 1969 a las 23:00:00 GMT, es decir, una hora antes de la época. Este es el negativo del desplazamiento de la zona horaria.

public static Date mergeDate(Date date, Time time) {
    long tzoffset = -(Time.valueOf("00:00:00").getTime());
    return new Date(date.getTime() + time.getTime() + tzoffset);
}

Por supuesto, todo esto es un truco sucio, que es necesario porque insistes en interpretar el valor del Tiempo como un lapso de tiempo, mientras que en realidad es un punto en el tiempo.

contestado el 10 de mayo de 11 a las 22:05

No puedo pensar en una mejor manera de "fusionar" una FECHA (sin información de "hora") con una Hora Sql (sin información de "fecha"). Necesito comparar fechas, y una de las fuentes es una tabla SQL que me da una FECHA y una HORA que debo armar. - marcolopes

En su lugar, puede usar esto.

   public static Date getDate(Date date, Time time) {
        Calendar calendar=Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
        calendar.setTime(date);
        calendar.add(Calendar.MILLISECOND, (int) time.getTime());
        return calendar.getTime();
    }

contestado el 10 de mayo de 11 a las 18:05

Lo siento, funciona, pero obtengo una hora menos. Martes 10 de mayo 00:00:00 BST 2011 y 03:58:44 = Martes 10 de mayo 02:58:44 BST 2011 - marcolopes

Eso es porque necesita configurar la zona horaria correctamente. use el método setTimezone () del calendario. - Manoj

Estoy confundido ... ¿java.util.date no contiene la zona horaria? - marcolopes

Puedes hacer

java.util.Date newDate = new java.util.Date(sqlDate.getTime());

contestado el 10 de mayo de 11 a las 17:05

Ese fue mi primer intento ... devuelve: Thu Jan 01 03:59:26 GMT 1970: - \ Entonces, la HORA está bien, pero restablece todos los demás campos. - marcolopes

java.sql.Time es un java.util.Date ;-) - Jeremy

prueba estos

 public static Date getDate(Date date, Time time) {
            Calendar calendar=Calendar.getInstance();
            calendar.setTime(date);
            Calendar calendar1=Calendar.getInstance();
            calendar1.setTime(time);
            calendar.set(Calendar.MINUTE, calendar1.get(Calendar.MINUTE));
            calendar.set(Calendar.SECOND, calendar1.get(Calendar.SECOND));
            calendar.set(Calendar.HOUR_OF_DAY, calendar1.get(Calendar.HOUR_OF_DAY));
            return calendar.getTime();
        }

Respondido 09 ago 11, 13:08

Le recomiendo que use java.time, la API moderna de fecha y hora de Java, para su trabajo de fecha y hora. Si no puede evitar obtener la fecha como java.util.Date (una clase que no representa una fecha) y tu hora del día como java.sql.Time, convierta ambos a tipos modernos y combínelos desde allí.

Java 8 y posterior

    // Time zone to use throughout
    ZoneId zone = ZoneId.systemDefault();
    
    // Initialize values to be used for demonstration
    Instant startOfDay = LocalDate.of(2011, Month.MAY, 10)
            .atStartOfDay(zone)
            .toInstant();
    Date date = Date.from(startOfDay);
    Time time = Time.valueOf(LocalTime.of(3, 58, 44));
    
    // Do work
    LocalTime localTime = time.toLocalTime();
    LocalDateTime combination = date.toInstant()
            .atZone(zone)
            .toLocalDate()
            .atTime(localTime);
    
    // Print result
    System.out.println(combination);

Salida:

2011-05-10T03:58:44

Sólo si es indispensable un Date, normalmente para una API heredada que no puede permitirse actualizar a java.time en este momento, vuelva a convertir:

    Instant inZone = combination.atZone(zone).toInstant();
    Date oldfashionedDate = Date.from(inZone);
    System.out.println(oldfashionedDate);

En mi zona horaria, la salida es:

Martes 10 de mayo a las 03:58:44 CEST de 2011

Java 6 y 7

Para Java 6 y 7 use el backport de java.time, ThreeTen Backport (enlaces en la parte inferior). Para el backport necesitamos usar DateTimeUtils para convertir a tipos modernos:

    LocalTime localTime = DateTimeUtils.toLocalTime(time);
    LocalDateTime combination = DateTimeUtils.toInstant(date)
            .atZone(zone)
            .toLocalDate()
            .atTime(localTime);

La salida es la misma que antes. Además, si necesita volver a convertir a un Date, Utilizar DateTimeUtils:

    Instant inZone = combination.atZone(zone).toInstant();
    Date oldfashionedDate = DateTimeUtils.toDate(inZone);

Nuevamente, la salida es la misma que antes.

Enlaces

Respondido el 06 de Septiembre de 20 a las 11:09

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.