new localdatetime initialize java java-8 java.util.date datetime-conversion zoneddatetime

java - localdatetime - ¿Cómo convertir ZonedDateTime a la fecha?



new zoneddatetime java (8)

Estoy tratando de establecer una fecha y hora agnóstica 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 db es Cassandra y el controlador db para Java solo comprende el tipo de fecha.

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 a la clase de fecha "heredada"?


tl; dr

java.util.Date.from( // Transfer the moment in UTC, truncating any microseconds or nanoseconds to milliseconds. Instant.now() ; // Capture current moment in UTC, with resolution as fine as nanoseconds. )

Aunque no había ningún punto en ese código anterior. Tanto java.util.Date como Instant representan un momento en UTC, siempre en UTC. El código anterior tiene el mismo efecto que:

new java.util.Date() // Capture current moment in UTC.

No hay beneficio aquí para usar ZonedDateTime . Si ya tiene un ZonedDateTime , ajústelo a UTC extrayendo un Instant .

java.util.Date.from( // Truncates any micros/nanos. myZonedDateTime.toInstant() // Adjust to UTC. Same moment, same point on the timeline, different wall-clock time. )

Otra respuesta correcta

La Answer de ssoltanid aborda correctamente su pregunta específica, cómo convertir un objeto java.time de la nueva escuela ( ZonedDateTime ) en un objeto java.util.Date vieja escuela. Extraiga el Instant del ZonedDateTime y pase a java.util.Date.from() .

Pérdida de datos

Tenga en cuenta que sufrirá pérdida de datos , ya que Instant seguimiento de nanoseconds desde la epoch mientras que java.util.Date seguimiento de milliseconds desde la época.

Su pregunta y comentarios plantean otros problemas.

Mantener servidores en UTC

Sus servidores deben tener su sistema operativo host configurado en UTC como una práctica recomendada en general. La JVM recoge 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 seleccionar la configuración del host, se pasa una bandera al iniciar una JVM puede establecer otra zona horaria. Peor aún: cualquier código en cualquier subproceso 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.

Tipo de Timestamp Cassandra

Cualquier base de datos y controlador decentes deben manejar automáticamente el ajuste de una fecha y hora pasada a UTC para el almacenamiento. No uso Cassandra, pero parece tener algún soporte rudimentario para la fecha y hora. La documentación dice que su tipo de Timestamp es un recuento de milisegundos de la misma época (primer momento de 1970 en UTC).

ISO 8601

Además, Cassandra acepta entradas de cadena en los formatos estándar ISO 8601 . Afortunadamente, java.time utiliza formatos ISO 8601 como valores predeterminados para analizar / generar cadenas. La implementación de la clase Instant '' toString bien.

Precisión: milisegundos vs nanosecord

Pero primero necesitamos reducir la precisión de nanosegundos de ZonedDateTime a milisegundos. Una forma es crear un Instante nuevo usando milisegundos. Afortunadamente, java.time tiene algunos métodos útiles para convertir ay desde milisegundos.

Código de ejemplo

Aquí hay un código de ejemplo en Java 8 Update 60.

ZonedDateTime zdt = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) ); … Instant instant = zdt.toInstant(); Instant instantTruncatedToMilliseconds = Instant.ofEpochMilli( instant.toEpochMilli() ); String fodderForCassandra = instantTruncatedToMilliseconds.toString(); // Example: 2015-08-18T06:36:40.321Z

O de acuerdo con este documento del controlador Cassandra Java , puede pasar una instancia de java.util.Date (que no debe confundirse con java.sqlDate ). Por lo tanto, puede hacer un juDate a partir de ese instantTruncatedToMilliseconds en el código anterior.

java.util.Date dateForCassandra = java.util.Date.from( instantTruncatedToMilliseconds );

Si haces esto a menudo, podrías hacer una frase.

java.util.Date dateForCassandra = java.util.Date.from( zdt.toInstant() );

Pero sería mejor crear un pequeño método de utilidad.

static public java.util.Date toJavaUtilDateFromZonedDateTime ( ZonedDateTime zdt ) { Instant instant = zdt.toInstant(); // Data-loss, going from nanosecond resolution to milliseconds. java.util.Date utilDate = java.util.Date.from( instant ) ; return utilDate; }

Observe 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 ZonedDateTime a UTC. Pero eso no es necesario. Conceptualmente:

ZonedDateTime = Instant + ZoneId

Simplemente extraemos la parte Instant, que ya está en UTC (básicamente en UTC, lea el documento de la clase para obtener detalles precisos).

Sobre java.time

El marco java.time está integrado en Java 8 y java.time posteriores. Estas clases suplantan a las antiguas y problemáticas clases de fecha y hora legacy , 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 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 necesita cadenas, no necesita clases java.sql.* .

¿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. Puede encontrar algunas clases útiles aquí, como Interval , YearWeek , YearQuarter y more .


Aquí hay un ejemplo que convierte la hora actual del sistema a UTC. Implica formatear ZonedDateTime como String y luego el objeto String se analizará en un objeto date usando java.text DateFormat.

ZonedDateTime zdt = ZonedDateTime.now(ZoneOffset.UTC); final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss"); final DateFormat FORMATTER_YYYYMMDD_HH_MM_SS = new SimpleDateFormat("yyyyMMdd HH:mm:ss"); String dateStr = zdt.format(DATETIME_FORMATTER); Date utcDate = null; try { utcDate = FORMATTER_YYYYMMDD_HH_MM_SS.parse(dateStr); }catch (ParseException ex){ ex.printStackTrace(); }


Para una aplicación acoplada como beehuang comentó, debe configurar su zona horaria.

Alternativamente, puede usar conZoneSameLocal . Por ejemplo:

2014-07-01T00: 00 + 02: 00 [GMT + 02: 00] se convierte por

Date.from(zonedDateTime.withZoneSameLocal(ZoneId.systemDefault()).toInstant())

al martes 01 de julio 00:00:00 CEST 2014 y por

Date.from(zonedDateTime.toInstant())

al lunes 30 de junio 22:00:00 UTC 2014


Puede convertir ZonedDateTime a un instante, que puede usar directamente con Date.

Date.from(java.time.ZonedDateTime.now().toInstant());


Puede hacerlo utilizando las clases java.time integradas en Java 8 y java.time posteriores.

ZonedDateTime temporal = ... long epochSecond = temporal.getLong(INSTANT_SECONDS); int nanoOfSecond = temporal.get(NANO_OF_SECOND); Date date = new Date(epochSecond * 1000 + nanoOfSecond / 1000000);


Si está utilizando el backport ThreeTen para Android y no puede utilizar el Date.from(Instant instant) más Date.from(Instant instant) (que requiere un mínimo de API 26) puede usar:

ZonedDateTime zdt = ZonedDateTime.now(); Date date = new Date(zdt.toInstant().toEpochMilli());

o:

Date date = DateTimeUtils.toDate(zdt.toInstant());

Lea también los consejos en la respuesta de Basil Bourque


Si solo le interesa ahora, simplemente use:

Date d = new Date();


Yo uso esto.

public class TimeTools { public static Date getTaipeiNowDate() { Instant now = Instant.now(); ZoneId zoneId = ZoneId.of("Asia/Taipei"); ZonedDateTime dateAndTimeInTai = ZonedDateTime.ofInstant(now, zoneId); try { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateAndTimeInTai.toString().substring(0, 19).replace("T", " ")); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }

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. Debe establecer su zona horaria correcta en el Código. Por ejemplo, Asia / Taipei. Luego corregirá en AWS o Docker o GCP.

public class App { public static void main(String[] args) { Instant now = Instant.now(); ZoneId zoneId = ZoneId.of("Australia/Sydney"); ZonedDateTime dateAndTimeInLA = ZonedDateTime.ofInstant(now, zoneId); try { Date ans = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateAndTimeInLA.toString().substring(0, 19).replace("T", " ")); System.out.println("ans="+ans); } catch (ParseException e) { } Date wrongAns = Date.from(java.time.ZonedDateTime.ofInstant(now, zoneId).toInstant()); System.out.println("wrongAns="+wrongAns); } }