在 Java 11 中,時鐘系統使用毫秒精度,但顯然在 Java 13 及更高版本中,它使用微秒精度,這導致我的測驗失敗。例如,OffsetDateTime.now()
當我從資料庫“2021-12-10T10:58:05.309595 01:00”讀取此日期時,給我這個日期“2021-12-10T10:58:05.309594500 01:00”。我正在尋找一種方法,我可以以它們應該相等的方式格式化第一個日期。我確實希望在 OffsetDateTime 型別而不是字串中使用它。
更新:我意識到當我將 java 版本從 11 升級到 17 而不是在本地時會出現這個問題,當 gitlab 運行測驗時我遇到了這個問題。
這是測驗:
@Test
fun `can store, find and delete a failed-message`() {
// given: a failed-message
val failedMessage = FailedMessage(
failedMessageId = FailedMessageId("the-subcription", "the-message-id"),
messageAttributes = mapOf("one" to "een", "two" to "twee"),
messagePayload = "message-payload",
exception = "exception",
dateTime = OffsetDateTime.now(),
stackTrace = "stackey tracey"
)
failedMessageRepository.store(failedMessage)
assertEquals(failedMessage, failedMessageRepository.find(failedMessage.failedMessageId))
}
由于日期時間不相等,此測驗失敗。這是日志:
<FailedMessage(failedMessageId=the-subcription-the-message-id, messageAttributes={one=een, two=twee}, messagePayload=message-payload, exception=exception, dateTime=2021-12-10T10:58:05.309594500 01:00, stackTrace=stackey tracey)>
but was:
<FailedMessage(failedMessageId=the-subcription-the-message-id, messageAttributes={one=een, two=twee}, messagePayload=message-payload, exception=exception, dateTime=2021-12-10T10:58:05.309595 01:00, stackTrace=stackey tracey)>
請你幫助我好嗎?
uj5u.com熱心網友回復:
AnOffsetDateTime
始終具有納秒級精度。它的now
方法可能沒有取決于平臺和 Java 版本。物件內部有。所以沒有辦法讓OffsetDateTime
秒數少于 9 位小數。
列印多少位小數是一個不同的問題。列印 an 時真正列印的OffsetDateTime
是String
. 如果您只是列印物件,toString
則隱式呼叫其方法以生成我們在列印中看到的字串。OffsetDateTime.toString()
總是為我們提供盡可能多的 3 位小陣列,以呈現完整的精度。因此,如果小數是.100000000
,則.100
列印。如果它們是.309594500
,正如您已經看到的那樣,所有 9 位小數都出現在字串中。您無法改變這種行為。
如果您想列印不同的字串,您可以使用DateTimeFormatter
帶有您喜歡的小數位數的a 。
那么你可以做什么:
- 您可以修改
OffsetDateTime
,或者實際上,您可以像舊的一樣創建一個新的,但只有更多的小數為零,這反過來可能會導致toString()
. - 您可以將 格式化
OffsetDateTime
為您喜歡的字串。
以下代碼片段結合了這兩個選項。為了僅將小數格式化為最后一個非零小數,我使用以下格式化程式:
private static final DateTimeFormatter ODT_FORMATTER = new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-dd'T'HH:mm.ss")
.appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
.appendOffsetId()
.toFormatter(Locale.ROOT);
示范:
OffsetDateTime dateTime = OffsetDateTime.parse("2021-12-10T10:58:05.309594500 01:00");
int nanos = dateTime.getNano();
OffsetDateTime with7Decimals = dateTime.withNano(nanos / 100 * 100);
System.out.println("toString(): " with7Decimals);
System.out.println("Formatted: " with7Decimals.format(ODT_FORMATTER));
OffsetDateTime with5Decimals = dateTime.withNano(nanos / 10000 * 10000);
System.out.println("toString(): " with5Decimals);
System.out.println("Formatted: " with5Decimals.format(ODT_FORMATTER));
輸出:
toString(): 2021-12-10T10:58:05.309594500 01:00 Formatted: 2021-12-10T10:58.05.3095945 01:00 toString(): 2021-12-10T10:58:05.309590 01:00 Formatted: 2021-12-10T10:58.05.30959 01:00
對于您的測驗,我認為沒有理由使用字串進行比較。只需OffsetDateTime
在將這些小數設定為零后比較物件,無論如何都會丟失資料庫中的物件。
編輯:測驗失敗的解決方法?以下行是您以比資料庫可以存盤的精度更高的精度獲取當前時間的地方。
dateTime = OffsetDateTime.now(),
因此,將其更改為僅提供您的資料庫支持的精度:
dateTime = OffsetDateTime.now().truncatedTo(ChronoUnit.MICROS),
這應該會導致節省和檢索時間而無需任何進一步的舍入。
為什么會出現這個問題? OffsetDateTime.now()
在不同的平臺和 Java 版本上有不同的精度。我不知道在任何平臺上 Java 11 和 13 之間有什么區別,但是沒有理由不應該有一個,并且在即將到來的版本中可能會有另一個。此外,如果您在 Linux、Windows 和 Mac 之間切換,即使使用相同的 Java 版本,您也可能會遇到差異。問題的另一部分是您的資料庫精度有限,或者更準確地說,是您在資料庫中用于存盤時間的資料型別。如果您使用的是timestamp with time zone
,則您可能擁有資料庫所能提供的最佳精度。顯然,您的資料庫具有微秒精度(秒為 6 位小數)和 Java 13OffsetDateTime.now()
至少有半微秒(500 納秒)的精度。因此,從 Java 13 開始,您將獲得資料庫無法存盤的值。顯然,您的資料庫或資料庫驅動程式然后將您的情況下的值四舍五入。這導致從資料庫檢索回的值與您嘗試保存的值不完全相同。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/382546.html
標籤:爪哇 约会时间 java-11 java-17 偏移日期时间
下一篇:R日期時間序列缺失值