截断到微秒
显然,我们不能将 a 的纳秒分辨率压缩到MySQL 数据类型Instant
的微秒分辨率和.DateTime
Timestamp
虽然我不使用 MySQL,但我想JDBC 驱动程序被构建为在接收时忽略纳秒Instant
,将值截断为微秒。我建议你尝试一个实验来看看,也许检查你的驱动程序的源代码是否符合 JDBC 4.2 及更高版本。
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 ) ;
……和……</p>
Instant instant2 = myResultSet.getObject( … , Instant.class ) ;
JDBC 4.2 规范需要支持但奇怪的OffsetDateTime
是不需要两种更常用的类型,Instant
以及ZonedDateTime
. 如果您的JDBC 驱动程序不支持Instant
,请转换。
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`.
然后比较。
Boolean result = instant.equals( instant2 ) ;
System.out.println( "instant: " + instant + " equals instant2: = " + instant2 + " is: " + result ) ;
您明智地担心从数据库中提取的值与原始值不匹配。如果您的业务问题可以接受,一种解决方案是将原始数据中的任何纳秒级截断为微秒级。我一般推荐这种方法。
java.time类提供了一种方法truncatedTo
。传递一个ChronoUnit
枚举对象来指定粒度。在这种情况下,那将是ChronoUnit.MICROS
.
Instant instant = Instant().now().truncatedTo( ChronoUnit.MICROS ) ;
目前这种方法应该足够了,因为您的数据中不太可能有任何纳秒。据我所知,今天的主流计算机不具备能够捕获纳秒的硬件时钟。
从纪元开始计数
如果您无法承受丢失任何可能存在的纳秒级数据,请使用从纪元开始计数。
我通常建议不要将日期时间作为从纪元参考日期开始的计数。但是,您几乎没有其他选择将基于纳秒的值存储在数据库中,例如 MySQL 和 Postgres,仅限于基于微秒的值。
存储整数对
我建议不要使用自 1970-01-01T00:00Z 之类的纪元以来的大量纳秒,我建议遵循Instant
类内部采用的方法:使用一对数字。
将整秒数作为整数存储在数据库中。在第二列中,将小数秒中的纳秒数存储为整数。
您可以轻松地从对象中提取/注入这些数字Instant
。只涉及简单的 64 位long
数字;不需要BigDecimal
or BigInteger
。我想您也许可以对这两个数字中的至少一个使用 32 位整数列。但为了简单起见,我会选择 64 位整数列类型,并与java.time.Instant
类的 long 对直接兼容。
long seconds = instant.getEpochSecond() ;
long nanos = instant.getNano() ;
……和……</p>
Instant instant = Instant.ofEpochSecond( seconds , nanos ) ;
按时间顺序排序时,您需要进行多级排序,首先在整个 seconds 列上排序,然后在 nanos fraction-of-second 列上进行第二次排序。