要解析多種格式,您可以創建大量DateTimeParser
實例,並將所有實例加入到一個格式化程序中(而不是一個接一個地嘗試)。
這將需要一個DateTimeFormatterBuilder
,這也將被用來強制執行一個特定數量的數字輸入(不幸的是,沒有辦法強制執行一個特定數量的數字,就像你只想使用DateTimeFormat.forPattern()
)。
首先創建大量org.joda.time.format.DateTimeParser
實例(每個可能的圖案):
// only yyyy
DateTimeParser p1 = new DateTimeFormatterBuilder()
// year with exactly 4 digits
.appendYear(4, 4).toParser();
// yyyy-MM-dd
DateTimeParser p2 = new DateTimeFormatterBuilder()
// year with exactly 4 digits
.appendYear(4, 4)
// rest of the pattern
.appendPattern("-MM-dd").toParser();
// yyyy MMM
DateTimeParser p3 = new DateTimeFormatterBuilder()
// year with exactly 4 digits
.appendYear(4, 4)
// rest of the pattern
.appendPattern(" MMM").toParser();
然後創建所有這些模式陣列,並創建一個DateTimeFormatter
它:
// create array with all the possible patterns
DateTimeParser[] possiblePatterns = new DateTimeParser[] { p1, p2, p3 };
DateTimeFormatter parser = new DateTimeFormatterBuilder()
// append all the possible patterns
.append(null, possiblePatterns)
// use the locale you want (in case of month names and other locale sensitive data)
.toFormatter().withLocale(Locale.ENGLISH);
我也使用Locale.ENGLISH
(因爲你也在你的問題的代碼中使用它)。此區域表示月份名稱將以英文顯示(因此MMM
可以分析像Jan
和Sep
這樣的值)。有了這個,你可以解析輸入:
System.out.println(parser.parseLocalDateTime("2014")); // OK
System.out.println(parser.parseLocalDateTime("201400")); // exception
System.out.println(parser.parseLocalDateTime("2014-10-10")); // OK
System.out.println(parser.parseLocalDateTime("201400-10-10")); // exception
System.out.println(parser.parseLocalDateTime("2014 Jul")); // OK
System.out.println(parser.parseLocalDateTime("201400 Jul")); // exception
當今年是2014
,代碼工作正常。當它的201400
,它拋出一個java.lang.IllegalArgumentException
,如:
java.lang.IllegalArgumentException異常:無效的格式爲: 「201400」 在 「00」
DateTimeFormatter
畸形是不可變的和線程安全的,所以每次調用驗證方法時都不需要創建它。您可以在方法外創建它(例如在static final
字段中)。
這比每次執行驗證時創建一個格式化程序並在出現異常時轉到下一個更好。創建的格式化程序已經在內部完成了,直到找到一個可用的模式(或者在所有模式失敗時拋出異常)。
新的Java日期/時間API
喬達時間是在修的模式,正在被新的API所取代,所以我不建議開始使用它的新項目。即使在joda's website它說:「請注意,喬達時間被認爲是一個很大程度上」完成「的項目。計劃沒有重大改進。如果使用Java SE 8,請遷移到java.time(JSR-310)。「。
如果您不能(或不想)從Joda-Time遷移到新的API,那麼您如果您使用的Java 可以忽略
這一部分,可以考慮使用new java.time API。它很容易,less bugged and less error-prone than the old APIs。
如果您使用的Java 6或7,則可以使用ThreeTen Backport,爲Java 8的新日期/時間類提供了一個很好的支持。而對於Android,你還需要ThreeTenABP(更多關於如何使用它here)。
下面的代碼適用於兩者。 唯一的區別是包名(在Java中8 java.time
和ThreeTen反向移植(或Android的ThreeTenABP)爲org.threeten.bp
),但類和方法名是相同的。
這個新的API是比以往更嚴格,所以格式化只與數字的確切人數(注意,有些課程是非常相似的喬達時間)工作原理:
// 4 digits in year
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy", Locale.ENGLISH);
fmt.parse("2014"); // OK
fmt.parse("201400"); // exception
fmt.parse("201"); // exception
此代碼與2014
工作,但與201400
或201
(或不正是4位其他值),它拋出一個異常:
java.time.format.DateTimeParseException:文本「201400」不能在索引0
解析
有了這個,您的驗證代碼可以使用字符串數組。
這裏只有一個細節:解析爲日期時,喬達時設置的默認值時,輸入所沒有的一些領域(如一個月變得月份,天變爲1,時/分/秒的設置爲零等)。
如果你只是驗證輸入,那麼你不需要返回任何東西。只要檢查是否拋出異常,你就會知道輸入是否有效。
如果你只需要一年的值,不過,你可以使用Year
class:
DateTimeFormatter parser = DateTimeFormatter.ofPattern("yyyy", Locale.ENGLISH);
System.out.println(Year.parse("2014", parser)); // ok
System.out.println(Year.parse("201400", parser)); // exception
如果你想在一年價值爲int
:
Year year = Year.parse("2014", parser);
int yearValue = year.getValue(); // 2014
但是,如果你想要獲取日期對象,您需要手動設置默認值 - 新API非常嚴格,並且不要自動設置這些值。在這種情況下,您必須使用DateTimeFormatterBuilder
來設置默認值。
我還它解析爲LocalDateTime
,就像例如:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// string pattern
.appendPattern("yyyy")
// default month is January
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
// default day is 1
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
// default hour is zero
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
// default minute is zero
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
// set locale
.toFormatter(Locale.ENGLISH);
// create LocalDateTime
System.out.println(LocalDateTime.parse("2014", fmt)); // 2014-01-01T00:00
System.out.println(LocalDateTime.parse("201400", fmt)); // exception
你可以選擇你想要作爲默認的字段的任何值,並且使用任何new available date types的。
爲什麼不只是解析'substr(date,0,4)'? – GriffeyDog
@GriffeyDog因爲我不認爲201400是有效的日期,所以我必須拋出異常。 – micdcar
字符串的長度沒有告訴你嗎? –