使用Java的对象时,最简单的方法是将它们存储为MySql 对象(以UTC为基准)。但是随着切换到,这种方法将不再适用,因为MySQL 不提供存储纳秒精度的功能。仅仅截断它们可能会导致新创建的对象与从数据库中读取的对象之间出现意外的比较结果。
时间戳并不是一种优雅的解决方案:手动编写选择查询变得更加困难,因为您必须在所有地方转换时间戳以使其可读,并且与甚至值相比,Java中的处理方式有些笨拙。
那么在这里最好的方法是什么呢?很可能不是,对吧?
那么在这里最好的方法是什么呢?很可能不是,对吧?
显然,我们无法将Instant
的纳秒分辨率压缩到MySQL数据类型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 ) ;
…和…
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 ) ;
truncatedTo
方法。传递一个ChronoUnit
枚举对象以指定粒度。在这种情况下,应该使用ChronoUnit.MICROS
。Instant instant = Instant().now().truncatedTo( ChronoUnit.MICROS ) ;
目前这种方法应该足够,因为您的数据中不太可能有任何纳秒。据我所知,今天的主流计算机没有配备能够捕获纳秒的硬件时钟。
如果您不能承受可能存在的任何纳秒数据丢失,请使用从纪元开始计数的方法。
通常我建议不要将日期时间跟踪为从纪元参考日期开始的计数。但是,在将基于纳秒的值存储在仅限于微秒级值的数据库(如MySQL和Postgres)中时,您几乎没有其他选择。
与其使用自1970-01-01T00:00Z以来的极大纳秒数作为纪元,我建议采用Instant
类内部采用的方法:使用一对数字。
在数据库中将整个秒数存储为整数。在第二列中,将分数秒中的纳秒数存储为整数。
您可以轻松地从/向Instant
对象提取/注入这些数字。只涉及简单的64位long
数字;不需要BigDecimal
或BigInteger
。我想您可能能够使用32位整数列来表示两个数字中的至少一个。但为了简单起见并且与java.time.Instant
类的一对长整型直接兼容,我会选择64位整数列类型。
long seconds = instant.getEpochSecond() ;
long nanos = instant.getNano() ;
…和…
Instant instant = Instant.ofEpochSecond( seconds , nanos ) ;
Instant
转换为使用ZoneOffset.UTC
偏移量的OffsetDateTime
并使用uuuu-MM-dd'T'HH:mm.ss.SSSSSSSSSX
格式化它,那么 (1) 直到 9999 年,您的字符串将始终是 30 个字符 (2) 字符串可以直接解析回Instant
(3) 字符串的顺序将与实例的顺序相同,(4) 您数据库中的字符串将比纯数字更易读。 - Ole V.V.Instant
的文档也不鼓励依赖它们。我只是想避免在运行时创建的Instant
与从数据库存储和重新加载的这个Instant
不相等的情况,因为纳秒丢失了。这是一个未记录的副作用,可能会破坏单元测试或更糟。 - NotX