Análise de data Java com precisão de microssegundo ou nanossegundo

De acordo com a documentação da class SimpleDateFormat , o Java não suporta granularidade de tempo acima de milissegundos em seus padrões de data.

Então, uma string de data como

  • 2015-05-09 00: 10: 23.999750900 // Os últimos 9 dígitos denotam nanossegundos

quando analisado através do padrão

  • símbolos aaaa-MM-dd HH: mm: ss.SSSSSSSSS // 9 ‘S’

Na verdade, interpreta o número inteiro após o . símbolo como (quase 1 bilhão!) milissegundos e não como nanossegundos, resultando na data

  • 2015-05-20 21:52:53 UTC

ou seja, mais de 11 dias à frente. Surpreendentemente, usar um número menor de símbolos S ainda resulta em todos os 9 dígitos sendo analisados ​​(em vez de, digamos, o mais à esquerda, 3 para .SSS ).

Existem duas maneiras de lidar com esse problema corretamente:

  • Use o pré-processamento de cadeias
  • Use uma implementação SimpleDateFormat personalizada

Haveria alguma outra maneira de obter uma solução correta simplesmente fornecendo um padrão para a implementação SimpleDateFormat padrão, sem outras modificações de código ou manipulação de string?

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. 

Não

Não, você não pode usar SimpleDateFormat para manipular nanossegundos .

Mas sua premissa que …

Java não suporta granularidade de tempo acima de milissegundos em seus padrões de data

… Não é mais verdade a partir do Java 8 , 9, 10 e posterior com as classs java.time internas . E também não é verdade no Java 6 e no Java 7, já que a maior parte da funcionalidade java.time é portada de volta .

java.time

SimpleDateFormat e as classs java.util.Date / .Calendar relacionadas agora são .Calendar pelo novo pacote java.time encontrado no Java 8 ( Tutorial ).

As novas classs java.time suportam resolução de nanossegundos . Esse suporte inclui a análise e geração de nove dígitos de segundo fracionário. Por exemplo, quando você usa a API java.time.format DateTimeFormatter , a letra de padrão S indica uma “fração do segundo” em vez de “milissegundos” e pode lidar com valores de nanossegundos.

Instant

Por exemplo, a class Instant representa um momento no UTC . Seu método toString gera um object String usando o formato padrão ISO 8601 . O Z no final significa UTC, pronunciado “Zulu”.

 instant.toString() // Generate a `String` representing this moment, using standard ISO 8601 format. 

2013-08-20T12: 34: 56.123456789Z

Observe que a captura do momento atual no Java 8 é limitada a uma resolução de milissegundos. As classs java.time podem conter um valor em nanossegundos, mas só podem determinar a hora atual com milissegundos. Essa limitação é devido à implementação do Clock . No Java 9 e posteriores, uma nova implementação do Clock pode capturar o momento atual em resolução mais fina, dependendo dos limites do hardware e do sistema operacional do seu host, geralmente microssegundos na minha experiência.

 Instant instant = Instant.now() ; // Capture the current moment. May be in milliseconds or microseconds rather than the maximum resolution of nanoseconds. 

LocalDateTime

Sua string de input de exemplo de 2015-05-09 00:10:23.999750900 não possui um indicador de fuso horário ou deslocamento de UTC. Isso significa que não representa um momento, não é um ponto na linha do tempo. Em vez disso, representa momentos potenciais ao longo de um intervalo de cerca de 26-27 horas, o intervalo de fusos horários em todo o mundo.

Pares uma input como um object LocalDateTime . Primeiro, substitua o SPACE no meio por um T para atender ao formato ISO 8601, usado por padrão ao analisar / gerar strings. Portanto, não há necessidade de especificar um padrão de formatação.

 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

A class java.sql.Timestamp também lida com resolução de nanossegundos, mas de uma maneira estranha. Geralmente é melhor fazer o seu trabalho dentro das classs java.time. Não há necessidade de usar o Timestamp novamente a partir do JDBC 4.2 e posterior.

 myPreparedStatement.setObject( … , instant ) ; 

E recuperação.

 Instant instant = myResultSet.getObject( … , Instant.class ) ; 

Se estiver usando um driver JDBC pré-4.2 mais antigo, você poderá usar toInstant e, a from methods, alternar entre java.sql.Timestamp e java.time.


Sobre o java.time

O framework java.time está embutido no Java 8 e posterior. Essas classs substituem as antigas classs herdadas de data e hora legadas , como java.util.Date , Calendar e SimpleDateFormat .

O projeto Joda-Time , agora em modo de manutenção , aconselha a migration para as classs java.time .

Para saber mais, veja o Oracle Tutorial . E pesquise o Stack Overflow para muitos exemplos e explicações. A especificação é JSR 310 .

Você pode trocar objects java.time diretamente com seu database. Use um driver JDBC compatível com o JDBC 4.2 ou posterior. Não há necessidade de strings, não há necessidade de classs java.sql.* .

Onde obter as classs java.time?

  • Java SE 8 , Java SE 9 , Java SE 10 e posterior
    • Construídas em.
    • Parte da API Java padrão com uma implementação integrada.
    • O Java 9 adiciona alguns resources e correções menores.
  • Java SE 6 e Java SE 7
    • Grande parte da funcionalidade java.time é transferida para o Java 6 e 7 no ThreeTen-Backport .
  • Android
    • Versões posteriores das implementações do pacote Android das classs java.time .
    • Para Android anterior (<26), o projeto ThreeTenABP adapta o ThreeTen-Backport (mencionado acima). Veja Como usar o ThreeTenABP… .

O projeto ThreeTen-Extra estende java.time com classs adicionais. Este projeto é um campo de testes para possíveis futuras adições ao java.time. Você pode encontrar algumas classs úteis aqui como Interval , YearWeek , YearQuarter e muito mais .