Trunkera till mikrosekunder
Uppenbarligen kan vi inte klämma in nanosekunderna
upplösning av en Instant
till mikrosekunder
upplösning av MySQL-datatyperna DateTime
och Timestamp
.
Även om jag inte använder MySQL, föreställer jag mig JDBC-drivrutinen
är byggd för att ignorera nanosekunderna när du tar emot en Instant
, trunkerar värdet till mikrosekunder. Jag föreslår att du provar ett experiment för att se, och kanske undersöker källkoden för din drivrutin som överensstämmer med JDBC 4.2 och senare.
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 ) ;
…och…
Instant instant2 = myResultSet.getObject( … , Instant.class ) ;
JDBC 4.2-specifikationen
kräver stöd för OffsetDateTime
men kräver konstigt nog inte de två vanligare typerna, Instant
och ZonedDateTime
. Om din JDBC-drivrutin
stöder inte Instant
, konvertera.
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`.
Jämför sedan.
Boolean result = instant.equals( instant2 ) ;
System.out.println( "instant: " + instant + " equals instant2: = " + instant2 + " is: " + result ) ;
Du är klokt nog bekymrad över att värden hämtade från databasen inte matchar det ursprungliga värdet. En lösning, om den är acceptabel för ditt affärsproblem, är att trunkera eventuella nanosekunder till mikrosekunder i dina ursprungliga data. Jag rekommenderar detta tillvägagångssätt generellt.
java.time klasser erbjuder en truncatedTo
metod. Skicka en ChronoUnit
enum-objekt för att ange granulariteten. I det här fallet skulle det vara ChronoUnit.MICROS
.
Instant instant = Instant().now().truncatedTo( ChronoUnit.MICROS ) ;
För närvarande bör detta tillvägagångssätt räcka eftersom du sannolikt inte har några nanosekunder i din data. Dagens vanliga datorer har inga hårdvaruklockor som kan fånga nanosekunder, så vitt jag vet.
Räkna från epok
Om du inte har råd att förlora någon nanosekundsdata som kan finnas, använd en räkne-från-epok.
Jag brukar rekommendera att inte spåra datum-tid som en räkning från ett epokreferensdatum. Men du har få andra val när det gäller att lagra dina nanosekundbaserade värden i en databas som MySQL och Postgres begränsade till mikrosekundsbaserade värden.
Lagra par med heltal
Istället för att använda det extremt stora antalet nanosekunder sedan en epok som 1970-01-01T00:00Z, föreslår jag att man följer det tillvägagångssätt som använts av internerna i Instant
klass:Använd ett par av siffror.
Lagra ett antal hela sekunder som ett heltal i din databas. I en andra kolumn lagras antalet nanosekunder i bråksekunden som ett heltal.
Du kan enkelt extrahera/injicera dessa nummer från/till ett Instant
objekt. Endast enkla 64-bitars long
siffror är inblandade; inget behov av BigDecimal
eller BigInteger
. Jag antar att du kanske kan använda en 32-bitars heltalskolumn för minst ett av de två talen. Men jag skulle välja 64-bitars heltalskolumntyper för enkelhetens skull och för direkt kompatibilitet med java.time.Instant
klassens långa par.
long seconds = instant.getEpochSecond() ;
long nanos = instant.getNano() ;
…och…
Instant instant = Instant.ofEpochSecond( seconds , nanos ) ;
När du sorterar kronologiskt måste du sortera på flera nivåer, först sortera hela sekundkolumnen och sedan sortera i andra hand på nanos bråkdel-av-sekund-kolumnen.