簡體   English   中英

將符合 ISO 8601 的字符串轉換為 ZonedDateTime

[英]Converting ISO 8601-compliant String to ZonedDateTime

我正在解析來自不同來源的日志,我正在從日志中提取日期時間字符串。 現在我想把它轉換成 java ZonedDateTime。

這里的問題是,我不知道確切的日期時間格式,我只知道,字符串將符合 ISO-8601。 所以我想像這樣寫 function :

    /**
     * @param _dateTime : any ISO 8601 format , e.g 1. %Y-%m-%dT%H:%M:%s%z => 2014-05-25T08:20:03.123456Z , 
     *                    e.g 2. %Y-%m-%dT%H:%M:%s => 2014-05-25T08:20:03.123456, e.g 3. %Y-%m-%d %H:%M:%s%z => 2014-11-08 15:55:55.123456Z, 
     *                    e.g 4. %Y-%m-%d %H:%M:%s => 2014-11-08 15:55:55
     * @return Instance of ZonedDateTime if conversion successful
     * @throws DateTimeParseException
     */
    private ZonedDateTime parse (String _dateTime) throws DateTimeParseException  {
        // Magic here.
    }

在 java 中最好的方法是什么?

這不是微不足道的好吧。 大多數魔法都在以下格式化程序中:

private static final DateTimeFormatter formatter
        = new DateTimeFormatterBuilder().append(DateTimeFormatter.ISO_LOCAL_DATE)
                .appendPattern("['T'][' ']")
                .append(DateTimeFormatter.ISO_LOCAL_TIME)
                .appendPattern("[XX]")
                .toFormatter();

此格式化程序接受

  • 2014-05-25這樣的日期。
  • 一個T或一個空格(或兩者或兩者都沒有,但我指望它們中的一個恰好在你的字符串中)。 方括號表示格式的可選部分。 單引號表示文字部分並導致T不被解釋為模式字母。
  • 一天中的某個時間。 ISO_LOCAL_TIME接受帶和不帶小數的秒。
  • 可選的 UTC 偏移量,如Z (為零)或-0600

對於字符串中沒有偏移量的情況,我們還需要一個時區。 例如:

private static final ZoneId defaultZone = ZoneId.of("America/Curacao");

您的方法仍然需要做的是區分有和沒有 UTC 偏移的情況。 帶有偏移量的表單可以直接解析為ZonedDateTime 沒有的不能,所以我們需要解析成LocalDateTime並轉換。

/**
 * @param dateTime : any ISO 8601 format , e.g 1. %Y-%m-%dT%H:%M:%s%z => 2014-05-25T08:20:03.123456Z , 
 *                    e.g 2. %Y-%m-%dT%H:%M:%s => 2014-05-25T08:20:03.123456, 
 *                    e.g 3. %Y-%m-%d %H:%M:%s%z => 2014-11-08 15:55:55.123456Z, 
 *                    e.g 4. %Y-%m-%d %H:%M:%s => 2014-11-08 15:55:55
 * @return Instance of ZonedDateTime if conversion successful
 * @throws DateTimeParseException
 */
private static ZonedDateTime parse(String dateTime) {
    // Little magic here.
    TemporalAccessor parsed = formatter.parseBest(dateTime,
            ZonedDateTime::from, LocalDateTime::from);
    if (parsed instanceof ZonedDateTime) {
        return (ZonedDateTime) parsed;
    } else {
        return ((LocalDateTime) parsed).atZone(defaultZone);
    }
}

讓我們試試看。 我已經使用了你的四個例子,加上我在第一個和第二個之間添加的一個。

    System.out.println(parse("2014-05-25T08:20:03.123456Z"));
    System.out.println(parse("2014-05-25T10:20:03.123456+0200"));
    System.out.println(parse("2014-05-25T08:20:03.123456"));
    System.out.println(parse("2014-11-08 15:55:55.123456Z"));
    System.out.println(parse("2014-11-08 15:55:55"));

Output:

 2014-05-25T08:20:03.123456Z 2014-05-25T10:20:03.123456+02:00 2014-05-25T08:20:03.123456-04:00[America/Curacao] 2014-11-08T15:55:55.123456Z 2014-11-08T15:55:55-04:00[America/Curacao]

順便說一句,對於帶有 UTC 偏移量的字符串,更喜歡OffsetDateTime而不是ZonedDateTime 代碼將是相同的,除非您需要在atZone(defaultZone) ) 之后進一步轉換.toOffsetDateTime()在您沒有直接從解析中獲得OffsetDateTime的情況下。 ZonedDateTime用於日期和時間,時區如歐洲/布拉格。 OffsetDateTime用於具有 UTC 偏移量的日期和時間。 正如我所提到的, Z與 UTC 的偏移量為 0。

編輯:Arvind Kumar Avinash 在評論中的注釋非常有用和重要,值得正確回答:給未來訪客的一些注釋:

  1. [XX]替換為[XX][XXX]也將滿足 +02:00 之類的偏移量。
  2. 日期時間解析/格式化類型是區域設置敏感的,因此,始終建議將其與適用的區域設置一起使用,例如.toFormatter(Locale.ENGLISH)而不是.toFormatter()
  3. 如果您希望ZoneId的 ZoneId 被自動拾取,您可以使用ZoneId.systemDefault()

暫無
暫無

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

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