patterns localdatetime example convert java datetime html5 date-parsing rfc3339

localdatetime - java iso date format



¿Cómo puedo analizar los tiempos de datos de RFC 3339 con Java? (7)

Estoy tratando de analizar la fecha devuelta como un valor del campo de entrada datetime HTML5. Pruébalo en Opera para ver un ejemplo. La fecha de devolución se ve así: 2011-05-03T11:58:01Z .

Me gustaría analizar eso en un objeto de fecha u calendario de Java.

Lo ideal es que una solución tenga las siguientes cosas:

  • No hay bibliotecas externas (tarros)
  • Maneja todos los formatos RFC 3339 aceptables
  • Una cadena debe poder validarse fácilmente para ver si es una fecha RFC 3339 válida

tl; dr

Instant.parse( "2011-05-03T11:58:01Z" )

ISO 8601

En realidad, RFC 3339 no es más que un mero perfil de la norma actual, ISO 8601 .

El RFC es diferente porque viola intencionalmente la norma ISO 8601 para permitir un desplazamiento negativo de cero horas ( -00:00 ) y le da un significado semántico de "desplazamiento desconocido". Esa semántica me parece una muy mala idea. Aconsejo seguir las reglas ISO 8601 más sensibles. En ISO 8601, el hecho de no tener ningún desplazamiento significa que el desplazamiento es desconocido, un significado obvio, mientras que la regla RFC es abstracta.

Las clases modernas de java.time utilizan los formatos ISO 8601 de forma predeterminada al analizar / generar cadenas.

Su cadena de entrada representa un momento en UTC. La Z en el final es la abreviatura de Zulu y significa UTC.

Instant (no Date )

La clase moderna Instant representa un momento en UTC. Esta clase reemplaza java.util.Date y usa una resolución más fina de nanosegundos en lugar de milisegundos.

Instant instant = Instant.parse( "2011-05-03T11:58:01Z" ) ;

ZonedDateTime (no Calendar )

Para ver ese mismo momento a través del tiempo de reloj de pared utilizado por las personas de una determinada región (una zona horaria), aplique un ZoneId para obtener un ZonedDateTime . Esta clase ZonedDateTime reemplaza la clase java.util.Calendar .

ZoneId z = ZoneId.of( "Africa/Tunis" ) ; ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, same point on the timeline, different wall-clock time.

Mudado

Recomiendo encarecidamente evitar las clases de fecha y hora heredadas cuando sea posible. Pero si debe interactuar con el código antiguo que aún no se ha actualizado a java.time , puede realizar la conversión hacia adelante y hacia atrás. Llama nuevos métodos añadidos a las clases antiguas .

Instant sustituye a java.util.Date .

java.util.Date myJUDate = java.util.Date.from( instant ) ; // From modern to legacy. Instant instant = myJUDate.toInstant() ; // From legacy to modern.

ZonedDateTime reemplaza a GregorianCalendar .

java.util.GregorianCalendar myGregCal = java.util.GregorianCalendar.from( zdt ) ; // From modern to legacy. ZonedDateTime zdt = myGregCal.toZonedDateTime() ; // From legacy to modern.

Si tienes un java.util.Calendar que en realidad es un GregorianCalendar , cast.

java.util.GregorianCalendar myGregCal = ( java.util.GregorianCalendar ) myCal ; // Cast to the concrete class. ZonedDateTime zdt = myGregCal.toZonedDateTime() ; // From legacy to modern.

Preocupaciones por puntos

Con respecto a los problemas específicos de su pregunta ...

  • No hay bibliotecas externas (tarros)

Las clases java.time están integradas en Java 8, 9, 10 y posteriores. También se incluye una implementación en Android posterior. Para Java anterior y Android anterior, vea la siguiente sección de esta Respuesta.

  • Maneja todos los formatos RFC 3339 aceptables

Las diversas clases de java.time manejan todos los formatos ISO 8601 que conozco. Incluso manejan algunos formatos que desaparecieron misteriosamente de ediciones posteriores de la norma.

Para otros formatos, vea los métodos parse y toString de las diversas clases, como LocalDate , OffsetDateTime , etc. Además, busque ya que hay muchos ejemplos y discusiones sobre este tema.

  • Una cadena debe poder validarse fácilmente para ver si es una fecha RFC 3339 válida

Para validar las cadenas de entrada, atrape la DateTimeParseException .

try { Instant instant = Instant.parse( "2011-05-03T11:58:01Z" ) ; } catch ( DateTimeParseException e ) { … handle invalid input }

Acerca de java.time

El marco java.time está integrado en Java 8 y java.time posteriores. Estas clases sustituyen a las antiguas y problemáticas clases de fecha y hora como java.util.Date , java.util.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 busca para 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 cadenas, no se necesitan clases java.sql.* .

¿Dónde obtener las clases java.time?

  • Java SE 8 , Java SE 9 y posteriores
    • Incorporado.
    • Parte de la API de Java estándar con una implementación en paquete.
    • Java 9 agrega algunas características menores y correcciones.
  • Java SE 6 y Java SE 7
    • Gran parte de la funcionalidad de java.time está respaldada a Java 6 y 7 en ThreeTen-Backport .
  • Android
    • Versiones posteriores de las implementaciones de paquetes de Android de las clases java.time.
    • Para Android anterior (<26), el proyecto ThreeTenABP adapta ThreeTen-Backport (mencionado anteriormente). Vea Cómo usar ThreeTenABP… .

El proyecto ThreeTen-Extra extiende java.time con clases adicionales. Este proyecto es un terreno de prueba para posibles adiciones futuras a java.time. Puede encontrar algunas clases útiles aquí como Interval , YearWeek , YearQuarter , y more .


Acabo de encontrar que Google implementó el analizador Rfc3339 en la biblioteca de cliente HTTP de Google

https://github.com/google/google-http-java-client/blob/dev/google-http-client/src/main/java/com/google/api/client/util/DateTime.java

Probado Funciona bien para analizar el fragmento de tiempo de sub segundos.

import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Date; import com.google.api.client.util.DateTime; DateTimeFormatter formatter = DateTimeFormatter .ofPattern("yyyy-MM-dd''T''HH:mm:ss.SSS''Z''") .withZone(ZoneId.of("UTC")); @Test public void test1e9Parse() { String timeStr = "2018-04-03T11:32:26.553955473Z"; DateTime dateTime = DateTime.parseRfc3339(timeStr); long millis = dateTime.getValue(); String result = formatter.format(new Date(millis).toInstant()); assert result.equals("2018-04-03T11:32:26.553Z"); } @Test public void test1e3Parse() { String timeStr = "2018-04-03T11:32:26.553Z"; DateTime dateTime = DateTime.parseRfc3339(timeStr); long millis = dateTime.getValue(); String result = formatter.format(new Date(millis).toInstant()); assert result.equals("2018-04-03T11:32:26.553Z"); } @Test public void testEpochSecondsParse() { String timeStr = "2018-04-03T11:32:26Z"; DateTime dateTime = DateTime.parseRfc3339(timeStr); long millis = dateTime.getValue(); String result = formatter.format(new Date(millis).toInstant()); assert result.equals("2018-04-03T11:32:26.000Z"); }


Con el formato que tiene, por ejemplo, 2011-05-03T11: 58: 01Z, el siguiente código lo hará. Sin embargo, recientemente probé html5 datetime en Chrome y Opera, me dio 2011-05-03T11: 58Z -> no tengo la parte ss que no puede ser manejada por el código a continuación.

new Timestamp(javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar(date).toGregorianCalendar().getTimeInMillis());


Entonces, en principio, esto se haría usando diferentes patrones SimpleDateFormat .

Aquí una lista de patrones para las declaraciones individuales en RFC 3339 :

  • fecha-fullear: yyyy
  • fecha-mes: MM
  • fecha-mday: dd
  • hora-hora: HH
  • tiempo-minuto: mm
  • tiempo-segundo: ss
  • time-secfrac: .SSS ( S significa milisegundos, sin embargo, no está claro qué pasaría si hubiera más o menos de 3 dígitos de estos).
  • time-numoffset: (como parece que no se admite +02:00 , en su lugar es compatible con los formatos +0200 , GMT+02:00 y algunas zonas horarias con nombre usando z y Z ).
  • compensación de tiempo: ''Z'' (no es compatible con otras zonas horarias) - debe usar format.setTimezone(TimeZone.getTimeZone("UTC")) antes de usar esto.)
  • tiempo parcial: HH:mm:ss o HH:mm:ss.SSS .
  • a tiempo completo: HH:mm:ss''Z'' o HH:mm:ss.SSS''Z'' .
  • fecha completa: yyyy-MM-dd
  • fecha y hora: yyyy-MM-dd''T''HH:mm:ss''Z'' o yyyy-MM-dd''T''HH:mm:ss.SSS''Z''

Como podemos ver, esto parece no poder analizar todo. Tal vez sería una mejor idea implementar un RFC3339DateFormat desde cero (usando expresiones regulares, por simplicidad, o análisis a mano, por eficiencia).


Tal vez no sea la forma más elegante, pero ciertamente una de las que hice recientemente:

Calendar cal = Calendar.getInstance(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss"); cal.setTime(sdf.parse(dateInString.replace("Z", "").replace("T", "-")));


Here hay un método simple para hacerlo. Puede satisfacer sus necesidades.


Date date = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss''Z''").parse(datetimeInFRC3339format)