在不损失精度的情况下从 Instant 转换为 XMLGregorianCalendar,反之亦然

Converting from Instant to XMLGregorianCalendar and vice-versa without losing precision

使用 java.time.Instantjavax.xml.datatype.XMLGregorianCalendar,我试图在不丢失精度的情况下从一个转换为另一个。

为什么这个测试没有通过,如何解决?

class FooTest {
    @Test
    void shouldConvertBackToSameInstant() throws DatatypeConfigurationException {
        Instant initialInstant = Instant.now();
        XMLGregorianCalendar xmlGregorianCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(String.valueOf(initialInstant));
        Instant convertedInstant = xmlGregorianCalendar.toGregorianCalendar().toInstant();
        assertEquals(initialInstant, convertedInstant);
    }
}
org.opentest4j.AssertionFailedError: 
Expected :2021-03-10T08:34:30.700715078Z
Actual   :2021-03-10T08:34:30.700Z

为什么这个测试没有通过?

您的 XMLGregorianCalendar 已获得 Instant 的全部精度。有损的是您转换回 Instant。您正在通过调用 .toGregorianCalendar() 转换为 GregorianCalendarGreogrianCalendar 只有毫秒精度,所以这就是你失去精度的地方。

如何解决?

正如您对第一次转化进行 String 一样,您可以对相反的转化进行同样的操作:

    Instant convertedInstant = Instant.parse(xmlGregorianCalendar.toString());

现在你的测试通过了(它在我的 Java 9 上通过了)。

结束语

Instant 在秒(即纳秒)上的精度高达 9 位小数。 XMLGregorianCalendar 的精度几乎是无限的。因此,如果您已将 Instant 转换为 XMLGregorianCalendar,您就会知道它的精度不超过 9 位小数,因此您可以安全地将其转换回来。另一方面,如果您应该从某个地方获得精度更高(10 位小数或更多)的 XMLGregorianCalendar,则我向您展示的转换将失败并显示 DateTimeParseException.