2015-05-05 46 views
5

我想從Joda時間庫遷移到Java時間(Java 8)。 我無法在java.time從Joda時間庫遷移到Java時間(Java 8)

喬達ISO格式找到等價的ISODateTimeFormat.dateOptionalTimeParser()具有良好的解析器:

ISODateTimeFormat.dateTimeParser():通用 - 選擇基於分析的字符串解析器。 類似的: ISODateTimeFormat.dateOptionalTimeParser()

我發現很難將喬達時間更改爲java.time。 有人能指導我嗎?

例如:

String dateTimeString = "2015-01-01T12:29:22+00:00"; 
String dateTimeString2 = "2015-01-01T12:29:22"; 

當我使用約達時間解析這個字符串,然後

ISODateTimeFormat.dateTimeParser().withZone("EST") 

可以不作爲問題處理兩種。這在java時代相當於什麼?

使用java 8,帶有ISO_Zoned_date_time的ZonedDateTime不能同時處理這兩種情況。

+0

我可以問你爲什麼要遷移嗎? Joda-Time中存在一個特殊問題,您希望通過遷移來解決問題嗎?正如您在我的回答中所看到的,遷移可能是實際操作中的挑戰。如果您對Joda-Time沒有任何特殊問題,並且只想遷移,因爲Java-8更「現代」,那麼這可能不值得所有的努力。 –

+0

是的,你是對的。我們想要使用Java 8的所有現代功能,這就是爲什麼我們要遷移到Java 8的原因。 – Shishir

+3

@MenoHochschild從Java SE 8開始,用戶被要求遷移到java.time(JSR-310) 。_同樣來自現場_注意Joda-Time被認爲是一個大部分「完成」的項目。計劃沒有重大改進。如果使用Java SE 8,請遷移到java.time(JSR-310)._這些建議都出現在主頁上。如果使用Java8(或更高版本),遷移是明智的。 –

回答

8

不能使用以下模式使用預定義的格式,但你可以構建自己的一個(並將其分配給一個靜態常量):

static final DateTimeFormatter DATE_TIME_OPTIONAL_OFFSET = 
    DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss[xxx]"); 

注意:如果您解析只包含日期的輸入和時間但沒有偏移(並且沒有任何偏移/區域默認),那麼結果只能是LocalDateTime,而不是全局時間戳。

請注意方法withZone(...)的不同行爲。

約達時間

When parsing, this zone will be set on the parsed datetime.  
A null zone means of no-override. If both an override chronology 
and an override zone are set, the override zone will take precedence 
over the zone in the chronology. 

的Java-8(JSR-310)

When parsing, there are two distinct cases to consider. 
If a zone has been parsed directly from the text, perhaps because 
DateTimeFormatterBuilder.appendZoneId() was used, then this override Zone 
has no effect. If no zone has been parsed, then this override zone will 
be included in the result of the parse where it can be used to build 
instants and date-times. 

側註釋:約達-時間方法withOffsetParsed()是更接近於Java-8行爲。

更新:我現在已經做了我自己的測試。看到有時令人驚訝的結果。

System.out.println(System.getProperty("java.version")); // 1.8.0_31 

// parsing s1 with offset = UTC 
String s1 = "2015-01-01T12:29:22+00:00"; 

OffsetDateTime odt1 = DATE_TIME_OPTIONAL_OFFSET.parse(s1, OffsetDateTime::from); 
System.out.println(odt1); // 2015-01-01T12:29:22Z --- OK 

LocalDateTime ldt1 = DATE_TIME_OPTIONAL_OFFSET.parse(s1, LocalDateTime::from); 
System.out.println(ldt1); // 2015-01-01T12:29:22 --- OK 

ZonedDateTime zdt1 = DATE_TIME_OPTIONAL_OFFSET.withZone(ZoneId.of("America/New_York")).parse(s1, ZonedDateTime::from); 
System.out.println(zdt1); // 2015-01-01T12:29:22-05:00[America/New_York] --- seems to be a bug compared with the spec above, the parsed offset was overridden!!! 

// now parsing s2 without offset 
String s2 = "2015-01-01T12:29:22"; 

OffsetDateTime odt2 = DATE_TIME_OPTIONAL_OFFSET.parse(s2, OffsetDateTime::from); 
System.out.println(odt2); // 2015-01-01T12:29:22Z --- questionable, the offset Z is invented/guessed here 

LocalDateTime ldt2 = DATE_TIME_OPTIONAL_OFFSET.parse(s2, LocalDateTime::from); 
System.out.println(ldt2); // 2015-01-01T12:29:22 --- OK 

DATE_TIME_OPTIONAL_OFFSET.withZone(ZoneId.of("America/New_York")).parse(s2, ZonedDateTime::from); 
// throws an exception --- seems to be a bug compared with the spec above, the zone set was not accepted 

結論:

遷移時我會小心。細節決定成敗。也許更新的Java版本8u40同時糾正了一些顯示的問題(至少withZone()的行爲可能已被糾正 - 請參閱JDK-issue 8033662,但對於8u31,回程修復似乎已丟失?!)。您還應該注意到,在我的測試中,標有「EST」的「時區」被替換爲「America/New_York」,因爲「EST」不是公認的時區標識(它在美國是一個本地時區名稱縮寫)。

更新 - 最終的解決方案

後額外的測試驗證碼似乎在Java中8u31工作(假設UTC作爲默認的情況下,輸入丟失偏移):

static final DateTimeFormatter DATE_TIME_OPTIONAL_OFFSET = 
    DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss[xxx]");  
OffsetDateTime odt = 
    DATE_TIME_OPTIONAL_OFFSET.withZone(ZoneOffset.UTC).parse(input, OffsetDateTime::from); 
ZonedDateTime zdt = odt.toZonedDateTime(); // containing a fixed offset 
0

我與掙扎嘗試將ISODateTimeFormat.dateTimeParser()。parseDateTime(「...」)轉換爲基於Java 8 java.time設施的等效項。 最後我失敗了使用創建DateTimeFormatter重現喬達時間的ISODateTimeFormat的行爲,而是選擇了一個正則表達式爲基礎的方法:

private static final Pattern ISO_8601_PARSE = Pattern.compile(
     "(?<year>\\d{1,4})-(?<month>\\d{1,2})-(?<day>\\d{1,2})" 
     + "(T((?<hour>\\d{1,2})(\\:(?<minute>\\d{1,2})(\\:(?<second>\\d{1,2})(\\.(?<millis>\\d{1,3}))?Z?)?)?)?)?"); 

public static Date parseIso8601Date(String date) throws IllegalArgumentException { 
    Matcher matcher = ISO_8601_PARSE.matcher(date); 
    if (matcher.matches()) { 
     try { 
      String day = matcher.group("day"); 
      String month = matcher.group("month"); 
      String year = matcher.group("year"); 
      String hour = matcher.group("hour"); 
      String minute = matcher.group("minute"); 
      String second = matcher.group("second"); 
      String millis = matcher.group("millis"); 
      return Date.from(ZonedDateTime.of(
        Integer.valueOf(year), 
        Integer.valueOf(month), 
        Integer.valueOf(day), 
        hasText(hour) ? Integer.valueOf(hour) : 0, 
        hasText(minute) ? Integer.valueOf(minute) : 0, 
        hasText(second) ? Integer.valueOf(second) : 0, 
        (hasText(millis) ? Integer.valueOf(millis) : 0) * 1000000, // nanoOfSecond 
        ZoneOffset.UTC).toInstant()); 
     } catch (NumberFormatException e) { 
      throw new IllegalArgumentException("Failed to parse [" + date + "]: " + e, e); 
     } 
    } else { 
     throw new IllegalArgumentException("Failed to parse [" + date + "]; does not match pattern yyyy-MM-ddThh:mm:ss[.SSS]Z"); 
    } 
} 

這並不等於100%,但(即不支持「+ 00:00「風格的時區偏移,而是假設UTC),但它在解析字符串時的寬鬆程度非常接近。