首先,如果你正在開始一個新項目,我建議你使用新的日期時間API而不是joda-time(更多關於下面的內容)。無論如何,這是兩個解決方案。
約達時間
的問題是,該圖案Z
是偏移量(以像+0000
或-0100
格式),但是字符串EST
是時區短名稱,這是由圖案z
(解析請參閱jodatime javadoc瞭解更多詳情)。
所以,你需要一個可選部分的模式,可以同時接收一個或另一個。你可以用org.joda.time.format.DateTimeFormatterBuilder
這個類來完成。
首先,你需要創建的org.joda.time.format.DateTimeParser
(一個用於Z
,以及其他爲z
)2個實例,並將其添加爲可選的解析器。然後使用下面的代碼創建org.joda.time.format.DateTimeFormatter
。請注意,我用的也是java.util.Locale
,只是爲了確保它正確解析平日和月份名稱(這樣你就不會依賴於默認的語言環境,它可以在每個系統/設備的不同而不同):
// offset parser (for "+0000")
DateTimeParser offsetParser = new DateTimeFormatterBuilder().appendPattern("Z").toParser();
// timezone name parser (for "EST")
DateTimeParser zoneNameParser = new DateTimeFormatterBuilder().appendPattern("z").toParser();
// formatter for both patterns
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// append common pattern
.appendPattern("EEE, d MMM yyyy HH:mm:ss ")
// optional offset
.appendOptional(offsetParser)
// optional timezone name
.appendOptional(zoneNameParser)
// create formatter (use English Locale to make sure it parses weekdays and month names independent of JVM config)
.toFormatter().withLocale(Locale.ENGLISH)
// make sure the offset "+0000" is parsed
.withOffsetParsed();
// parse the strings
DateTime est = fmt.parseDateTime("Sat, 10 Jun 2017 12:49:45 EST");
DateTime utc = fmt.parseDateTime("Sun, 11 Jun 2017 18:18:23 +0000");
System.out.println(est);
System.out.println(utc);
輸出將是:
2017-06-10T12:49:45.000-04:00
2017-06-11T18:18:23.000Z
如果他們不完全像你期望的那樣(或者你還在犯錯誤),請看下面的註釋。
注:
注意EST
印刷作爲日期/時間與偏移-0400
。這是因爲EST
內部成爲America/New_York
時區,現在在夏令時,它的偏移量是-0400
(我可以通過做DateTimeZone.forTimeZone(TimeZone.getTimeZone("EST"))
來解決這個問題:問題是:這些3個字母的名稱是ambiguous and not standard,並且joda-time只是假設「 。默認」爲他們因此,如果你沒有想到這個時區,而你不希望依賴於默認,你可以使用地圖使用自定義值,就像這樣:
// mapping EST to some other timezone (I know it's wrong and Chicago is not EST, it's just an example)
Map<String, DateTimeZone> map = new LinkedHashMap<>();
map.put("EST", DateTimeZone.forID("America/Chicago"));
// parser for my custom map
DateTimeParser customTimeZoneParser = new DateTimeFormatterBuilder().appendTimeZoneShortName(map).toParser();
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// append common pattern
.appendPattern("EEE, d MMM yyyy HH:mm:ss ")
// optional offset
.appendOptional(offsetParser)
// optional custom timezone name
.appendOptional(customTimeZoneParser)
// optional timezone name (accepts all others that are not in the map)
.appendOptional(zoneNameParser)
// create formatter (use English Locale to make sure it parses weekdays and month names independent of JVM config)
.toFormatter().withLocale(Locale.ENGLISH)
// make sure the offset "+0000" is parsed
.withOffsetParsed();
System.out.println(fmt.parseDateTime("Sat, 10 Jun 2017 12:49:45 EST"));
這將解析EST
作爲America/Chicago
(我知道這是錯的,芝加哥不是EST
,這只是一個例子,你如何改變d efaults使用地圖),以及輸出將是:
2017-06-10T12:49:45.000-05:00
如果得到了與上面的第一個代碼的錯誤,則還可以使用此,映射EST
到所需的時區(取決於jodatime的版本和您正在使用的Java,EST
可能未映射到默認值並引發異常,因此使用自定義映射可以避免這種情況)。
新的日期時API
至於說在@Ole V.V.'s comment(我沒有時間昨天寫的),喬達時間正在被new Java's Date and Time API,這是遠遠優於compared to the old Date
and SimpleDateFormat
classes取代。
如果您使用Java> = 8,則java.time
軟件包已經是JDK的一部分。對於Java < = 7,有ThreeTen Backport。而對於Android,還有ThreeTenABP(更多關於如何使用它here)。
如果您正在開始一個新項目,請考慮使用新的API而不是joda-time,因爲在joda's website中寫着:請注意,Joda-Time被認爲是一個大部分「已完成」的項目。計劃沒有重大改進。如果使用Java SE 8,請遷移到java.time(JSR-310)。
下面的代碼適用於兩者。唯一的區別是軟件包名稱(在Java 8中爲java.time
,在ThreeTen Backport(或Android的ThreeTenABP)中爲org.threeten.bp
),但名稱的類別和方法是相同的。
的想法是非常相似jodatime,與細微差別:
- 您可以使用可選的段定界符
[]
- 一組具有自定義時區的名稱(映射
EST
一些有效的非曖昧時區)需要(如EST
沒有映射到任何默認)
- 一個新的類用於:
ZonedDateTime
,它表示日期和時間與時區(所以它涵蓋了你的情況下)
只是提醒的是,這些類是java.time
包(或org.threeten.bp
取決於你使用的Java版本,如上所述):
// set with custom timezone names
Set<ZoneId> set = new HashSet<>();
// when parsing, ambiguous EST uses to New York
set.add(ZoneId.of("America/New_York"));
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// append pattern, with optional offset (delimited by [])
.appendPattern("EEE, d MMM yyyy HH:mm:ss[ Z]")
// append optional timezone name with custom set for EST
.optionalStart().appendLiteral(" ").appendZoneText(TextStyle.SHORT, set).optionalEnd()
// create formatter using English locale to make sure it parses weekdays and month names correctly
.toFormatter(Locale.ENGLISH);
ZonedDateTime est = ZonedDateTime.parse("Sat, 10 Jun 2017 12:49:45 EST", fmt);
ZonedDateTime utc = ZonedDateTime.parse("Sun, 11 Jun 2017 18:18:23 +0000", fmt);
System.out.println(est); // 2017-06-10T12:49:45-04:00[America/New_York]
System.out.println(utc); // 2017-06-11T18:18:23Z
輸出將是:
2017-06-10T12:49:45-04:00[America/New_York]
2017-06-11T18:18:23Z
請注意,在第一種情況下,EST
設置爲America/New_York
(由自定義設置配置)。 appendZoneText
會訣竅,使用自定義集中的值來解決不明確的情況。
而第二種情況設置爲UTC,因爲偏移量爲+0000
。
如果你想第一個對象轉換爲UTC,它是簡單明瞭:
System.out.println(est.withZoneSameInstant(ZoneOffset.UTC)); // 2017-06-10T16:49:45Z
輸出將轉換爲UTC紐約的日期/時間:
2017-06-10T16:49:45Z
相反的ZoneOffset.UTC
,當然您可以使用任何時區或偏移量(使用ZoneId
和ZoneOffset
類,請檢查javadoc獲取更多詳細信息)。
如果你對外部庫很滿意,Joda-Time可能不是最糟糕的選擇,但你是否意識到Joda-Time已經進一步發展爲現代Java數據和時間API? Joda-Time人員正式推薦遷移,並且該API可在[ThreeTenABP](https://github.com/JakeWharton/ThreeTenABP)庫中用於Android。 –
@ OleV.V。你是對的,昨天我沒有時間寫新的日期時間API。無論如何,我已經在下面更新了[我的回答](https://stackoverflow.com/a/44490104/7605325),包括新API的示例。謝謝! –