簡體   English   中英

Java 8 DateTimeFormatter使用偏移拒絕正確的ISO 8601日期/時間

[英]Java 8 DateTimeFormatter rejects correct ISO 8601 date/time with offset

我使用DateTimeFormatter的格式字符串:uuuu-MM-dd'T'HH:mm:ssX

必須支持所有可能的時區偏移格式,包括:Z,00,00:00,0000

根據官方的DateTimeFormatter文檔,'X'限定符必須與這些格式的偏移匹配:

X區偏移'Z'表示零偏移-X Z; -08; -0830; -08:30; -083015; -08:30:15;

但事實上,事實並非如此

輸入字符串 :“2014-01-01T00:30:00 + 00:00”

resultjava.time.format.DateTimeParseException:無法解析文本'2014-01-01T00:30:00 + 00:00',在索引22處找到未解析的文本

輸入字符串 :“2014-01-01T00:30:00Z”

結果正確

編碼:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssX");
OffsetDateTime parsed = OffsetDateTime.parse(dateTimeAsString, formatter);

JDK 1.8.0_192(Oracle,而不是OpenJDK)

這有點復雜。 正如jvdmr所說 ,X的數量很重要。 XXXXX將識別-08:30:15 ,但不是-083015 XXXX將承認后者,但不承認前者。

為了考慮所有可能的示例格式,我們需要指定不同的可能性。 這可以使用方括號在格式模式字符串中完成。 這些包含可選部件。 一些實驗表明,以下模式涵蓋了所有示例:

uuuu-MM-dd'T'HH:mm:ss[XXXXX][XXXX][X]

我們來試試吧:

    DateTimeFormatter formatter
            = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss[XXXXX][XXXX][X]");
    for (String dts : new String[] {
            "2014-01-01T00:30:00-08:30:15", "2014-01-01T00:30:00-083015",
            "2014-01-01T00:30:00-08:30", "2014-01-01T00:30:00-0830",
            "2014-01-01T00:30:00-08", "2014-01-01T00:30:00Z",
    }) {
        System.out.println(OffsetDateTime.parse(dts, formatter));
    }

此代碼段的輸出是:

 2014-01-01T00:30-08:30:15 2014-01-01T00:30-08:30:15 2014-01-01T00:30-08:30 2014-01-01T00:30-08:30 2014-01-01T00:30-08:00 2014-01-01T00:30Z 

編輯

VelNaga建議不要對ISO日期時間格式進行硬編碼。 由於編寫格式模式字符串容易出錯,因此這可能是一個好主意。 例如:

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
            .appendPattern("[XXXXX][XXXX][X]")
            .toFormatter();

使用此格式化程序的輸出與使用上述格式化程序的輸出相同。 它更啰嗦,但我們很容易認為這是值得的,因為它不易出錯,可能更清晰,更容易閱讀。

文檔 (強調我的)

偏移X和x: 根據模式字母的數量格式化偏移 一個字母僅輸出小時,例如'+01',除非分鍾非零,在這種情況下分鍾也輸出,例如'+0130'。 兩個字母輸出小時和分鍾,沒有冒號,例如'+0130'。 三個字母輸出小時和分鍾,帶有冒號,例如'+01:30'。 四個字母輸出小時和分鍾以及可選秒,沒有冒號,例如'+013015'。 五個字母輸出小時和分鍾,可選秒輸出冒號,例如'+01:30:15'。 六個或更多字母拋出IllegalArgumentException。 當要輸出的偏移量為零時,模式字母“X”(大寫)將輸出“Z”,而模式字母“x”(小寫)將輸出“+00”,“+ 0000”或“+00” :00' 。

這也適用於解析日期。 您想要使用和不使用冒號進行解析,這意味着您必須使用可選節,因為沒有單個模式支持此選項。 嘗試這種模式: "uuuu-MM-dd'T'HH:mm:ss[XXX][XXXX]"

不要硬編碼任何ISO日期格式。 DateFormatter已經有一個ISO日期格式轉換的靜態方法。 使用以下代碼,

DateTimeFormatter formatter = DateTimeFormatter.ISO_ZONED_DATE_TIME;

OffsetDateTime parsed = OffsetDateTime.parse(dateTimeAsString,formatter);

它肯定會起作用。 請在此鏈接中找到更多格式化程序選項。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM