要解析多种格式,您可以创建大量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
字符串的长度没有告诉你吗? –