setear - Análisis de fechas Java con precisión de microsegundos o nanosegundos
operaciones con fechas en java (1)
De acuerdo con la
documentación de la clase SimpleDateFormat
,
Java
no admite la granularidad de tiempo por encima de milisegundos en sus patrones de fecha.
Entonces, una cadena de fecha como
- 2015-05-09 00: 10: 23.999750900 // Los últimos 9 dígitos denotan nanosegundos
cuando se analiza a través del patrón
- aaaa-MM-dd HH: mm: ss.SSSSSSSSS // 9 símbolos ''S''
en realidad interpreta el número entero después del
.
símbolo como (¡casi mil millones!) milisegundos y no como nanosegundos, lo que da como resultado la fecha
- 2015-05-20 21:52:53 UTC
es decir, más de 11 días de antelación.
Sorprendentemente, el uso de un número menor de símbolos
S
todavía da como resultado el análisis de los 9 dígitos (en lugar de, digamos, los 3 más a la izquierda para
.SSS
).
Hay 2 formas de manejar este problema correctamente:
- Usar preprocesamiento de cadenas
- Use una implementación personalizada de SimpleDateFormat
¿Habría alguna otra forma de obtener una solución correcta simplemente suministrando un patrón a la implementación estándar
SimpleDateFormat
, sin ninguna otra modificación de código o manipulación de cadenas?
tl; dr
LocalDateTime.parse( // With resolution of nanoseconds, represent the idea of a date and time somewhere, unspecified. Does *not* represent a moment, is *not* a point on the timeline. To determine an actual moment, place this date+time into context of a time zone (apply a `ZoneId` to get a `ZonedDateTime`).
"2015-05-09 00:10:23.999750900" // A `String` nearly in standard ISO 8601 format.
.replace( " " , "T" ) // Replace SPACE in middle with `T` to comply with ISO 8601 standard format.
) // Returns a `LocalDateTime` object.
no
No, no puede usar SimpleDateFormat para manejar nanoseconds .
Pero tu premisa es que ...
Java no admite granularidad de tiempo por encima de milliseconds en sus patrones de fecha
... ya no es cierto a partir de Java 8 , 9, 10 y posterior con las clases java.time integradas. Y tampoco es cierto para Java 6 y Java 7, ya que la mayor parte de la funcionalidad java.time tiene un puerto posterior .
java.time
SimpleDateFormat
y las clases relacionadas
java.util.Date
/
.Calendar
ahora están
.Calendar
moda por el nuevo paquete
java.time
que se encuentra en Java 8 (
Tutorial
).
Las nuevas clases java.time admiten resolución en
nanosecond
.
Ese soporte incluye el análisis y la generación de nueve dígitos de fracción de segundo.
Por ejemplo, cuando utiliza la API
java.time.format
DateTimeFormatter
, la letra del patrón
S
denota una "fracción del segundo" en lugar de "milisegundos", y puede hacer frente a valores de nanosegundos.
Instant
Como ejemplo, la clase
Instant
representa un momento en
UTC
.
Su método
toString
genera un objeto
String
utilizando el formato estándar
ISO 8601
.
La
Z
al final significa UTC, pronunciado "Zulu".
instant.toString() // Generate a `String` representing this moment, using standard ISO 8601 format.
2013-08-20T12: 34: 56.123456789Z
Tenga en cuenta que capturar el momento actual en Java 8 está limitado a una resolución de milisegundos.
Las clases
java.time
pueden
contener
un valor en nanosegundos, pero solo pueden determinar el tiempo actual con milisegundos.
Esta limitación se debe a la implementación de
Clock
.
En Java 9 y versiones posteriores, una nueva implementación de
Clock
puede capturar el momento actual en una resolución más fina, dependiendo de los límites de su hardware host y sistema operativo, generalmente
microseconds
en mi experiencia.
Instant instant = Instant.now() ; // Capture the current moment. May be in milliseconds or microseconds rather than the maximum resolution of nanoseconds.
LocalDateTime
Su cadena de entrada de ejemplo de
2015-05-09 00:10:23.999750900
carece de un indicador de zona horaria o desplazamiento desde UTC.
Eso significa que
no
representa un momento,
no
es un punto en la línea de tiempo.
En cambio, representa momentos
potenciales a
lo largo de un rango de aproximadamente 26-27 horas, el rango de zonas horarias de todo el mundo.
Pares como una entrada como un objeto
LocalDateTime
.
Primero, reemplace el ESPACIO en el medio con una
T
para cumplir con el formato ISO 8601, usado por defecto al analizar / generar cadenas.
Por lo tanto, no es necesario especificar un patrón de formato.
LocalDateTime ldt =
LocalDateTime.parse(
"2015-05-09 00:10:23.999750900".replace( " " , "T" ) // Replace SPACE in middle with `T` to comply with ISO 8601 standard format.
)
;
java.sql.Timestamp
La clase
java.sql.Timestamp
también maneja la resolución de nanosegundos, pero de una manera incómoda.
Generalmente es mejor hacer tu trabajo dentro de las clases java.time.
No es necesario volver a usar
Timestamp
a partir de JDBC 4.2 y posteriores.
myPreparedStatement.setObject( … , instant ) ;
Y recuperación.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
OffsetDateTime
La especificación JDBC no exige el soporte para
Instant
, pero
OffsetDateTime
.
Entonces, si el código anterior falla con su controlador JDBC, use lo siguiente.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;
Y recuperación.
Instant instant = myResultSet.getObject( … , OffsetDateTime.class ).toInstant() ;
Si usa un controlador JDBC anterior a 4.2, puede usar
toInstant
y los métodos para ir y venir entre
java.sql.Timestamp
y java.time.
Estos nuevos métodos de conversión se agregaron a las
antiguas
clases heredadas.
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?
-
Java SE 8
,
Java SE 9
,
Java SE 10
y posterior
- Incorporado.
- Parte de la API Java estándar con una implementación integrada.
- Java 9 agrega algunas características menores y correcciones.
-
Java SE 6
y
Java SE 7
- Gran parte de la funcionalidad java.time se transfiere 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 campo de pruebas para posibles adiciones futuras a java.time.
Puede encontrar algunas clases útiles aquí, como
Interval
,
YearWeek
,
YearQuarter
y
more
.