亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

解析 RFC 3339 日期時間時不考慮區域調整

解析 RFC 3339 日期時間時不考慮區域調整

動漫人物 2023-06-21 13:58:02
(從CodeReview遷移)我正在嘗試并試圖更好地理解 Java Time。我的代碼沒有按預期工作,我想問問原因,可能是因為我對 JSR-310 時區處理有誤解。我有一個時間戳字符串要解析DateTimeFormatterString text = "2019-08-28T10:39:57+02:00";DateTimeFormatter ISO_RFC_3339_PARSER = DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.of("Europe/Paris"));上述值是在服務器當地時間為中歐上午 10:39 時生成的。由于夏令時,UTC 時間為早上 8:39。您可以自己計算一下您所在區域的時間。當計算機的時區與時間戳中顯示的時區相同(+2)時,以下測試有效@Testpublic void testTimestamp(){? ? LocalDateTime time = ZonedDateTime.from(ISO_RFC_3339_PARSER.parse(text)).toLocalDateTime();? ? errorCollector.checkThat(time.getYear(), is(2019));? ? errorCollector.checkThat(time.getMonthValue(), is(8));? ? errorCollector.checkThat(time.getDayOfMonth(), is(28));? ? errorCollector.checkThat(time.getHour(), is(10));? ? errorCollector.checkThat(time.getMinute(), is(39));? ? errorCollector.checkThat(time.getSecond(), is(57));}我嘗試修改輸入字符串以更好地理解 Java 時間如何調整時區。但結果卻大錯特錯!我嘗試反復更改輸入字符串中的時區,因此測試失敗。例如,如果我將字符串更改為,2019-08-28T10:39:57+08:00則表示現在是巴黎凌晨 2 點。但在檢查一天中的小時時,上述測試代碼繼續通過。即結果中的LocalDateTime時間仍然是上午 10 點。問題為什么我的代碼仍然返回 10 作為當地時間,盡管我不斷更改源字符串中的時區?那么解析 RFC 3339 字符串(表示嵌入偏移中的瞬間)并將其轉換為LocalDateTime可能的區域調整對象的正確方法是什么?假設機器在 CE[S]T 時區運行。環境我需要將時間戳與計算機時間進行比較,并檢查它是否太舊。這意味著如果在歐洲評估美國時間,它可能不會“太舊”。
查看完整描述

2 回答

?
元芳怎么了

TA貢獻1798條經驗 獲得超7個贊

LocalDateTime從ZonedDateTime時區的簡單切割中獲取。它的價值無關緊要。您需要做的是將您的ZonedDateTime區域從+8 區轉換為+2 區,這將相應地改變時間。然后就可以LocalDateTime從你的修改中ZonedDateTime得到想要的效果了。這是一個演示它的示例:


private static void testDateParsing() {

    ZonedDateTime zdt = ZonedDateTime.parse("2019-08-28T10:39:57+08:00", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZZZZZ"));

    ZonedDateTime modifiedZdt = zdt.withZoneSameInstant(ZoneId.systemDefault());

    System.out.println(zdt);

    System.out.println(modifiedZdt);

    System.out.println(LocalDateTime.from(zdt));

    System.out.println(LocalDateTime.from(modifiedZdt));

}

輸出是:


2019-08-28T10:39:57+08:00

2019-08-28T05:39:57+03:00[Asia/Jerusalem]

2019-08-28T10:39:57

2019-08-28T05:39:57

請注意,我的本地時區是+03,而不是您的+02。


查看完整回答
反對 回復 2023-06-21
?
慕的地10843

TA貢獻1785條經驗 獲得超8個贊

? ? String text = "2019-08-28T10:39:57+02:00";

? ? OffsetDateTime time = OffsetDateTime.parse(text);

? ? System.out.println("Hour of day is " + time.getHour());

輸出是(如您所料):


一天中的小時是 10


嘗試不同的偏移量:


? ? String text = "2019-08-28T10:39:57+08:00";

一天中的小時是 10


所以仍然相同,仍然是字符串中給出的小時。這就是 10 的由來。我從你的代碼中選擇了一個稍微簡單的代碼示例,但它演示的行為與你的代碼相同,沒有區別,也足以解釋。


需要注意的一點是,代碼不依賴于 JVM 的時區設置(您報告為歐洲/巴黎)。那挺好的。這意味著,如果我們相信代碼是正確的,我們也可以相信它能夠在所有時區的所有 JVM 上正確運行。


LocalDateTime在您的代碼中,您通過調用轉換為toLocalDateTime(). 通常這種轉換沒有任何充分的理由,因為OffsetDateTime或ZonedDateTime很好地實現了目的。OffsetDateTime轉換的作用是保留或中的日期和時間(掛鐘時間)ZonedDateTime并丟棄偏移量或時區信息。因此,如果一天中的小時在轉換前為 10,則轉換后也將為 10。如果您期望轉換為當地時間(歐洲/巴黎),您可能會感到困惑。不執行此類轉換。Local在 java.time 名稱中意味著:沒有時區或偏移量。有人認為該詞的使用Local因為這個含義具有誤導性(從某種意義上說,它是歷史性的,因為它是從 java.time 的先驅 Joda-Time 接管的)。


那么解析 RFC 3339 字符串(表示嵌入偏移中的瞬間)并將其轉換為 LocalDateTime可能的區域調整對象的正確方法是什么?假設機器在 CE[S]T 時區運行。


解析已經可以正確地為您工作。您可能不需要轉換??梢灾苯颖容^。和的和方法在isBefore比較時會考慮不同的偏移量或時區,并將為您提供所需的結果。如果您確實想轉換:isEqualisAfterOffsetDateTimeZonedDateTime


? ? String text = "2019-08-28T10:39:57+08:00";

? ? OffsetDateTime time = OffsetDateTime.parse(text);

? ? System.out.println("Hour of day is " + time.getHour());


? ? ZoneId myTimeZone = ZoneId.of("Europe/Paris");

? ? ZonedDateTime timeInFrance = time.atZoneSameInstant(myTimeZone);

? ? System.out.println("Hour of day in France is " + timeInFrance.getHour());

Hour of day is 10

Hour of day in France is 4

同樣,您可以轉換為LocalDateTime并保留 4 點,但我不明白您為什么應該這樣做。


關于我對代碼的簡化:您的 RFC 3339 字符串包含與 UTC (+02:00) 的偏移量,而不是時區(如歐洲/巴黎或歐洲/羅馬)。所以用ZonedDateTime它來解析就有點矯枉過正了;OffsetDateTime是一個更好的選擇。字符串格式符合 ISO 8601。java.time 類可以直接解析最常見的 ISO 8601 格式變體,無需任何顯式格式化程序,因此我們在這里不需要格式化程序。順便說一句,您分配給格式化程序的區域沒有任何區別,因為使用了字符串中的偏移量。


查看完整回答
反對 回復 2023-06-21
  • 2 回答
  • 0 關注
  • 383 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號