Tronquer en microsecondes
Évidemment, nous ne pouvons pas presser les nanosecondes
résolution d'un Instant
dans les microsecondes
résolution des types de données MySQL DateTime
et Timestamp
.
Bien que je n'utilise pas MySQL, j'imagine le pilote JDBC
est construit pour ignorer les nanosecondes lors de la réception d'un Instant
, en tronquant la valeur en microsecondes. Je vous suggère d'essayer une expérience pour voir, et peut-être d'examiner le code source de votre pilote qui est conforme à JDBC 4.2 et versions ultérieures.
Instant instant = Instant.now().with( ChronoField.NANO_OF_SECOND , 123_456_789L ) ; //Set the fractional second to a spefic number of nanoseconds.
myPreparedStatement.setObject( … , instant ) ;
…et…
Instant instant2 = myResultSet.getObject( … , Instant.class ) ;
La spécification JDBC 4.2
nécessite la prise en charge de OffsetDateTime
mais curieusement, ne nécessite pas les deux types les plus couramment utilisés, Instant
et ZonedDateTime
. Si votre pilote JDBC
ne prend pas en charge Instant
, convertir.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ; // Use `OffsetDateTime` if your JDBC driver does not support `Instant`.
Instant instant2 = odt.toInstant() ; // Convert from `OffsetDateTime` to `Instant`.
Puis comparez.
Boolean result = instant.equals( instant2 ) ;
System.out.println( "instant: " + instant + " equals instant2: = " + instant2 + " is: " + result ) ;
Vous êtes sagement préoccupé par les valeurs tirées de la base de données qui ne correspondent pas à la valeur d'origine. Une solution, si elle est acceptable pour votre problème métier, consiste à tronquer toutes les nanosecondes en microsecondes dans vos données d'origine. Je recommande généralement cette approche.
Le java.time les classes offrent un truncatedTo
méthode. Passer un ChronoUnit
objet enum pour spécifier la granularité. Dans ce cas, ce serait ChronoUnit.MICROS
.
Instant instant = Instant().now().truncatedTo( ChronoUnit.MICROS ) ;
Actuellement, cette approche devrait suffire car il est peu probable que vous ayez des nanosecondes dans vos données. Les ordinateurs grand public d'aujourd'hui n'ont pas d'horloges matérielles capables de capturer des nanosecondes, pour autant que je sache.
Compter à partir de l'époque
Si vous ne pouvez pas vous permettre de perdre des données nanosecondes éventuellement présentes, utilisez un décompte à partir de l'époque.
Je recommande généralement de ne pas suivre la date-heure en tant que décompte à partir d'une date de référence d'époque. Mais vous avez peu d'autres choix pour stocker vos valeurs basées sur la nanoseconde dans une base de données telle que MySQL et Postgres limitées aux valeurs basées sur la microseconde.
Stocker une paire d'entiers
Plutôt que d'utiliser le très grand nombre de nanosecondes depuis une époque telle que 1970-01-01T00:00Z, je suggère de suivre l'approche adoptée par les internes de l'Instant
classe :utilisez une paire de nombres.
Stocker un nombre de entiers secondes sous forme d'entier dans votre base de données. Dans une deuxième colonne, stockez sous forme d'entier le nombre de nanosecondes dans la fraction de seconde.
Vous pouvez facilement extraire/injecter ces numéros depuis/vers un Instant
objet. Uniquement long
64 bits simples les chiffres sont impliqués ; pas besoin de BigDecimal
ou BigInteger
. Je suppose que vous pourrez peut-être utiliser une colonne d'entiers 32 bits pour au moins l'un des deux nombres. Mais je choisirais des types de colonnes entiers 64 bits pour plus de simplicité et pour une compatibilité directe avec le java.time.Instant
paire de longs de la classe.
long seconds = instant.getEpochSecond() ;
long nanos = instant.getNano() ;
…et…
Instant instant = Instant.ofEpochSecond( seconds , nanos ) ;
Lors d'un tri chronologique, vous devrez effectuer un tri à plusieurs niveaux, en triant d'abord sur la colonne des secondes entières, puis en triant ensuite sur la colonne nanos fraction de seconde.