簡體   English   中英

當模式和值都未知時,Java 8 DateTime API解析日期字符串

[英]Java 8 DateTime API parsing date string when both pattern and value are unknown

我需要使用一個未知但提供的日期時間格式來解析未知的日期時間字符串。 我想解析ZonedDateTime 如果模式字符串中沒有包含區域,我想假設UTC時區。 問題是,我不確定如何確定模式字符串是否包含時區信息,以便在創建DateTimeFormatter時可以附加.withZone(ZoneOffset.UTC) 該怎么做?

String dateTimeFormat = "yyyy-MM-dd HH:mm:ss Z"; // this will be unknown (could be any possible valid pattern)
String dateTimeValue = "2001-01-01 00:00:00 -0800"; // this will also be unknown

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateTimeFormat);
if(????) { // how to determine if the pattern contains timezone information
    dateTimeFormatter = dateTimeFormatter.withZone(ZoneOffset.UTC);
}

ZonedDateTime dateTime = ZonedDateTime.parse(dateTimeValue, dateTimeFormatter);

您的示例格式設置模式對於DateTimeFormatter類不正確。 例如,大寫字母YYYY表示基於周的年份,不太可能是發件人的意圖。 DD表示每年的日期(1-366),同樣不太可能是發件人的意圖。

DateTimeFormatter格式代碼

您將需要學習以這些字符串傳遞給您的代碼。 然后,您需要轉換為DateTimeFormatter類使用的正確格式模式代碼。

DateTimeFormatterBuilder

您可能會受益於使用非常靈活且功能強大的DateTimeFormatterBuilder類,您可以通過多個調用來構建格式。 在完成所有必要的調用之后,最后通過調用DateTimeFormatterBuilder::toFormatter生成DateTimeFormatter

搜索Stack Overflow以獲取使用此類的示例。

其他問題

如何確定模式字符串是否包含時區信息

傳遞的格式代碼中的Z告訴您。

我可以附加.withZone(ZoneOffset.UTC)

如果您嘗試調整為UTC,請將輸入字符串解析為日期時間對象后執行此操作。 要獲得UTC,只需調用toInstant ,因為根據定義, Instant始終為UTC。

我沒有調整到UTC,如果模式中沒有指定區域,我想將區域設置為UTC。

如果輸入字符串缺少任何時區指示符或從UTC偏移量,則解析為LocalDateTime 該類故意缺乏任何時區概念或從UTC偏移。 這樣, LocalDateTime 不代表時刻,是不是在時間軸上的一個點。

如果您確定知道沒有區域/偏移的字符串確實是用於特定區域/偏移,那么:

使用OffsetDateTimeZonedDateTime ,您現在有一個時刻,一個時間點。

區域和偏移有什么區別? 偏移量僅為幾小時 - 分鍾 - 秒,僅此而已。 一個區域,相反,是更多 區域是特定區域的人員使用的偏移的過去,現在和將來變化的歷史。

LocalDateTime ldt = LocalDateTime.parse( "2018-01-23T01:23:45.123" ) ;  // *Not* a moment, *not* a point on the timeline.
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ; // Assign an offset to determine a moment.

您似乎過分專注於解析作為應用業務邏輯的一種方式。 相反, 使您的解析盡可能簡單直接,以獲得與輸入匹配的java.time對象。 只有解析才能對日期時間值進行調整或轉換。 最后將此解析和轉換代碼與其他業務邏輯工作分開,因此您有三個不同的階段:(1)簡單/直接解析,(2)調整/轉換值,(3)將日期時間值用於業務目的。

ISO 8601

你的這個項目充滿了風險。 使用他們自己發明的格式代碼承擔其他人的任意字符串輸入的責任是我不願意做的事情。 成功或失敗是你無法控制的,因為你可能永遠不會知道會到達什么。

更明智的方法是將負擔轉移到此傳入數據的來源。 它們應該以標准ISO 8601格式傳遞您的字符串。 該標准是為此目的而設計的,將日期時間值作為文本進行交換。 標准格式巧妙地設計為明確的,並且易於通過機器解析,並且易於被不同文化的人閱讀。

在解析/生成字符串時, java.time類在默認情況下使用標准ISO 8601格式。 ZonedDateTime類通過在方括號中附加時區的名稱來明智地擴展標准。 如果發送分區值,我建議您的數據來源也這樣做 - 通常最好只交換UTC值。

沒有必要的if在所有。 如java doc中所述 ,只有在文本中找不到區域時才應用“覆蓋區域”。 (這使得詞覆蓋的選擇有點奇怪,但它是從格式化而不是解析的角度來看。)

您可以隨時設置它,它只會在需要時使用。

此外,偶然DateTimeFormatter是一個不可變類。 在您的示例中,withZone將不執行任何操作,因為您丟棄了它返回的對象。

一種識別方法是使用ZonedDateTime解析給定日期。 如果無法解析,則沒有時區信息。

  DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateTimeFormat);

    ZonedDateTime zonedDateTime = null;
    try{
      zonedDateTime  = ZonedDateTime.parse(dateTimeValue, dateTimeFormatter);
    } catch (DateTimeParseException e) {
      // if can't parse to ZoneDateTime
      LocalDateTime dateTime  = LocalDateTime.parse(dateTimeValue, dateTimeFormatter);
    }

暫無
暫無

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

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