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



使用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转换将失败。

最新更新