我使用Joda-Time解析这样的年代:
private DateTime attemptParse(String pattern, String date) {
DateTimeFormatter parser = DateTimeFormat.forPattern(pattern).withLocale(Locale.ENGLISH);
DateTime parsedDateTime = parser.parseLocalDateTime(date).toDateTime(WET);
return parsedDateTime;
}
我尝试解析多种格式:"yyyy-MM-dd", "yyyy-MMM-dd","yyyy MMM dd-dd","yyyy MMM", (etc), "yyyy"
。当一个人不工作时,我会尝试下一个。
当字符串确实只有4位数时(例如:"2016"
),它就像魅力一样。问题是我有时会收到这样的信息:"201400"
。 Joda-Time将此与"yyyy"
模式匹配,并返回年份201400
的日期。
我想避免丑陋的if if to check year > 9999
。有没有办法用Joda-Time做到这一点?
答案 0 :(得分:4)
要解析多种格式,您可以创建大量DateTimeParser
个实例,并将所有实例连接在一个格式化程序中(而不是一个接一个地尝试)。
这将需要DateTimeFormatterBuilder
,这也将用于在输入中强制执行特定数量的数字(遗憾的是,无法使用{{1}强制执行特定数量的数字})。
首先,您创建了许多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:格式无效:“201400”格式错误为“00”
java.lang.IllegalArgumentException
是不可变且线程安全的,因此每次调用验证方法时都不需要创建它。您可以在方法之外创建它(例如在DateTimeFormatter
字段中)。
这比每次执行验证时创建一个格式化程序更好,并在发生异常时转到下一个格式化程序。创建的格式化程序已在内部执行,转到下一个模式,直到找到一个有效的格式化程序(如果所有模式都失败,则抛出异常)。
Joda-Time处于维护模式,正在被新的API取代,因此我不建议使用它来启动新项目。即使在joda's website中它也说:“请注意,Joda-Time被认为是一个很大程度上”完成“的项目。没有计划大的增强。如果使用Java SE 8,请迁移到java.time(JSR) -310)。“即可。
如果您不能(或不想)从Joda-Time迁移到新API,则可以忽略此部分。
如果您使用的是 Java 8 ,请考虑使用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中为static final
而在ThreeTen Backport(或Android的ThreeTenABP中)为java.time
),但类和方法名称是一样的。
这个新API比以前的API严格得多,因此格式化程序只能使用确切的位数(请注意,某些类与Joda-Time非常相似):
org.threeten.bp
此代码适用于// 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
(或任何其他没有4位数的值)会抛出异常:
java.time.format.DateTimeParseException:无法在索引0处解析文本“201400”
有了这个,您的验证代码可以使用字符串数组。
只有一个细节:当解析为日期时,Joda-Time在输入没有某些字段时设置默认值(例如月份变为1月,白天变为1,小时/分钟/秒被设置为零等等)。
如果您只是验证输入,那么您不需要返回任何内容。只需检查是否抛出异常,您就会知道输入是否有效。
如果您只需要年份值,则可以使用Year
class:
201
如果您希望年份值为DateTimeFormatter parser = DateTimeFormatter.ofPattern("yyyy", Locale.ENGLISH);
System.out.println(Year.parse("2014", parser)); // ok
System.out.println(Year.parse("201400", parser)); // exception
:
int
但是如果你想获得一个日期对象,你需要手动设置默认值 - 新API非常严格,不要自动设置这些值。在这种情况下,您必须使用Year year = Year.parse("2014", parser);
int yearValue = year.getValue(); // 2014
。
我还将其解析为DateTimeFormatterBuilder
,例如:
LocalDateTime
您可以选择所需的任何值作为字段的默认值,并使用new available date types中的任何一个。
答案 1 :(得分:0)
你所说的是Jodatime应该以某种方式猜测它应该在2014年解析“201400”。我认为这不合理地属于该库的范围。您应该自己预处理数据,例如使用:
String normalizedDate = String.format("%4s", date).trim();