使用java.time.Instant
和javax.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()
,您将转换为GregorianCalendar
。GreogrianCalendar
只有毫秒级的精度,所以这就是你失去精度的地方。
如何修复?
就像您在第一次转换中使用String
一样,您可以对相反的转换执行相同的操作:
Instant convertedInstant = Instant.parse(xmlGregorianCalendar.toString());
现在你的测试通过了(在我的Java 9上通过了)。
结论
Instant
在秒(所以纳秒)上的精度高达9个小数。XMLGregorianCalendar
几乎得到了无限的精度。因此,如果您已经将Instant
转换为XMLGregorianCalendar
,那么您知道它的精度不会超过9位小数,因此可以安全地将其转换回来。另一方面,如果您应该从某处获得具有更高精度(10位小数或更多)的XMLGregorianCalendar
,那么我向您展示的DateTimeParseException
转换将失败。