Estoy tratando de establecer una fecha y hora independiente del servidor en mi base de datos y creo que la mejor práctica para hacerlo es establecer una fecha y hora UTC. Mi servidor de base de datos es Cassandra y el controlador de base de datos para Java comprende solo el tipo de fecha.
Entonces, asumiendo que en mi código estoy usando el nuevo Java 8 ZonedDateTime para obtener el UTC ahora ( ZonedDateTime.now(ZoneOffset.UTC)
), ¿cómo puedo convertir esta instancia de ZonedDateTime en la clase de fecha "heredada"?
java
java-8
java.util.date
datetime-conversion
zoneddatetime
Milen Kovachev
fuente
fuente
java.util.Date
yjava.sql.Date
.Respuestas:
Puede convertir ZonedDateTime en un instante, que puede usar directamente con Date.
fuente
Date
es un número de milisegundos desde la época, por lo que está relacionado con UTC. Si lo imprime , se utilizará la zona horaria predeterminada, pero la clase Date no tiene conocimiento de la zona horaria del usuario ... Consulte, por ejemplo, la sección "mapeo" en docs.oracle.com/javase/tutorial/datetime/iso/legacy .html Y LocalDateTime es explícitamente sin referencia a una zona horaria, lo que puede verse como confuso ...ZonedDateTime
. Lajava.time.Instant
clase es un reemplazo directo dejava.util.Date
, ambos representan un momento en UTC, aunqueInstant
usan una resolución más fina de nanosegundos en lugar de milisegundos.Date.from( Instant.now() )
debería haber sido tu solución. O para el caso,new Date()
que tiene el mismo efecto, capturando el momento actual en UTC.tl; dr
Aunque no tenía sentido en ese código anterior. Ambos
java.util.Date
yInstant
representan un momento en UTC, siempre en UTC. El código anterior tiene el mismo efecto que:No hay beneficio aquí para usar
ZonedDateTime
. Si ya tiene unZonedDateTime
, ajuste a UTC extrayendo unInstant
.Otra respuesta correcta
La respuesta de ssoltanid aborda correctamente su pregunta específica, cómo convertir un objeto java.time (
ZonedDateTime
) de la nueva escuela en un objeto de la vieja escuelajava.util.Date
. Extraiga elInstant
de ZonedDateTime y pase ajava.util.Date.from()
.Pérdida de datos
Tenga en cuenta que sufrirá pérdida de datos , ya que
Instant
rastrea nanosegundos desde época mientras quejava.util.Date
rastrea milisegundos desde época.Su pregunta y comentarios plantean otros problemas.
Mantener los servidores en UTC
Sus servidores deben tener su sistema operativo host configurado en UTC como una mejor práctica en general. La JVM toma esta configuración del sistema operativo host como su zona horaria predeterminada, en las implementaciones de Java que conozco.
Especificar zona horaria
Pero nunca debe confiar en la zona horaria predeterminada actual de la JVM. En lugar de elegir la configuración del host, una bandera que se pasa al iniciar una JVM puede establecer otra zona horaria. Peor aún: ¡Cualquier código en cualquier hilo de cualquier aplicación en cualquier momento puede hacer una llamada a
java.util.TimeZone::setDefault
para cambiar ese valor predeterminado en tiempo de ejecución!Timestamp
Tipo CassandraCualquier base de datos y controlador decente debería manejar automáticamente el ajuste de una fecha y hora pasada a UTC para el almacenamiento. No uso Cassandra, pero parece tener un soporte rudimentario para la fecha y la hora. La documentación dice que su
Timestamp
tipo es un recuento de milisegundos de la misma época (primer momento de 1970 en UTC).ISO 8601
Además, Cassandra acepta entradas de cadenas en los formatos estándar ISO 8601 . Afortunadamente, java.time usa formatos ISO 8601 como valores predeterminados para analizar / generar cadenas. La implementación de la
Instant
clase funcionarátoString
bien.Precisión: milisegundos vs nanosegundos
Pero primero debemos reducir la precisión de nanosegundos de ZonedDateTime a milisegundos. Una forma es crear un Instant fresco usando milisegundos. Afortunadamente, java.time tiene algunos métodos útiles para convertir desde y hacia milisegundos.
Código de ejemplo
Aquí hay un código de ejemplo en Java 8 Update 60.
O de acuerdo con este documento del controlador de Cassandra Java , puede pasar una
java.util.Date
instancia (que no debe confundirse conjava.sqlDate
). Entonces podrías hacer un juDate a partir de esoinstantTruncatedToMilliseconds
en el código anterior.Si haces esto con frecuencia, podrías hacer una sola línea.
Pero sería mejor crear un pequeño método de utilidad.
Note la diferencia en todo este código que en la Pregunta. El código de la pregunta intentaba ajustar la zona horaria de la instancia de ZonedDateTime a UTC. Pero eso no es necesario. Conceptualmente:
Simplemente extraemos la parte Instant, que ya está en UTC (básicamente en UTC, lea el documento de la clase para obtener detalles precisos).
Acerca de 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
, ySimpleDateFormat
.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 .
Puede intercambiar objetos java.time directamente con su base de datos. Utilice un controlador JDBC compatible con JDBC 4.2 o posterior. No se necesitan cuerdas, no se necesitan
java.sql.*
clases.¿Dónde obtener las clases java.time?
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 .fuente
Si está usando el backport ThreeTen para Android y no puede usar el más nuevo
Date.from(Instant instant)
(que requiere un mínimo de API 26), puede usar:o:
Lea también el consejo en la respuesta de Basil Bourque
fuente
DateTimeUtils
clase con los métodos de conversión, por lo que usaría Date date = DateTimeUtils.toDate (zdt.toInstant ()); `. No es de tan bajo nivel.A continuación, se muestra un ejemplo de conversión de la hora actual del sistema a UTC. Implica formatear ZonedDateTime como una cadena y luego el objeto String se analizará en un objeto de fecha utilizando java.text DateFormat.
fuente
Puede hacer esto usando las clases java.time integradas en Java 8 y posteriores.
fuente
Instant
s rastrea segundos y nanosegundos.Date
s rastrear milisegundos. Esta conversión de uno a otro es correcta.Yo uso esto.
Porque
Date.from(java.time.ZonedDateTime.ofInstant(now, zoneId).toInstant());
no es trabajo !!! Si ejecuta su aplicación en su computadora, no hay problema. Pero si ejecuta en cualquier región de AWS o Docker o GCP, generará un problema. Porque la computadora no es tu zona horaria en la nube. Debes configurar tu zona horaria correctamente en Code. Por ejemplo, Asia / Taipei. Luego se corregirá en AWS o Docker o GCP.fuente
ans=Mon Jun 18 01:07:56 CEST 2018
, que es incorrecto, y luegowrongAns=Sun Jun 17 17:07:56 CEST 2018
, que es correcto.La respuesta aceptada no funcionó para mí. La fecha devuelta es siempre la fecha local y no la fecha de la zona horaria original. Vivo en UTC + 2.
Se me han ocurrido dos formas alternativas de obtener la fecha correcta de un ZonedDateTime.
Digamos que tiene este ZonedDateTime para Hawái
o para UTC como se pidió originalmente
Alternativa 1
Podemos usar java.sql.Timestamp. Es simple pero probablemente también hará mella en la integridad de su programación.
Alternativa 2
Creamos la fecha a partir de milisegundos (respondida aquí anteriormente). Tenga en cuenta que ZoneOffset local es imprescindible.
fuente
Para una aplicación de ventana acoplable como Beehuang comentó, debe establecer su zona horaria.
Alternativamente, puede usar withZoneSameLocal . Por ejemplo:
2014-07-01T00: 00 + 02: 00 [GMT + 02: 00] se convierte por
hasta el martes 01 de julio a las 00:00:00 CEST de 2014 y hasta
al lun 30 jun 22:00:00 UTC 2014
fuente
Si solo está interesado en ahora, simplemente use:
fuente