最近开始使用WEB UI。并遇到了日期字符串的问题 解析/验证。 " DD-MM-YYYY" 我找到的一些方法是:
匹配 - 未完成验证,不灵活。
(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])
有一篇文章,其中有人建议使用可能的日期字符串预初始化Set - 快速,有效,但也不灵活且耗费内存
是否有更容易的东西,可能在公共图书馆中提供?
请不要建议使用SimpleDateFormat :)
更新 对于java 8正确答案 是https://stackoverflow.com/a/43076001/1479668
答案 0 :(得分:3)
如果您使用的是Java 8,那么DateTimeFormatter就是您要找的。 javadoc的链接还包含示例代码和许多预定义格式。此外,您还可以定义自己的。
这是一些代码,来自同一链接的一个例子:
LocalDate date = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
String text = date.format(formatter);
LocalDate parsedDate = LocalDate.parse(text, formatter);
此外,这个How to parse/format dates with LocalDateTime? (Java 8)问题得到了一些很棒的答案。
编辑:感谢Basil Bourque ,了解有关ThreeTen-Backport项目的更新,以防在某些旧版本的java中需要使用java 8提供的几乎相同的功能。
答案 1 :(得分:3)
序言:
如果您不关心细节,那么建议DateTimeFormatter.ofPattern("yyyy MM dd");
的接受答案是正常的。否则,如果您对解析的棘手细节感兴趣,请进一步阅读:
正则表达式
正如您已经认识到的那样,使用(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])
之类的正则表达式无法进行完整的验证。例如,此表达式将接受“2017-02-31”(2月31天???)。
Java-8解析机制
然而,Java-8-class DateTimeFormatter
只能通过解析使这些不存在的日期无效。为了详细说明,我们必须区分语法验证和日历验证。第一种语法验证由方法parseUnresolved()执行。
解析实现为两阶段操作。首先,文本是 使用格式化程序定义的布局解析,生成Map of 字段到值,ZoneId和年表。其次,解析的数据是 通过验证,组合和简化各个领域来解决 更有用的。此方法执行解析阶段但不执行 解决阶段。
此方法的主要优点是不使用异常流程,这使得这种解析速度很快。但是,解析的第二步使用异常流,另请参阅方法parse(CharSequence, ParsePosition)
的{{3}}。
相比之下,如果是,则此方法将抛出DateTimeParseException 发生错误,包含错误索引的异常。这个 由于复杂性的增加,行为的改变是必要的 解析和解析此API中的日期/时间。
恕我直言的表现限制。另一个缺点是当前可用的API不允许像在正则表达式中那样指定点或连字符。 API只提供类似“[。] [ - ]”的构造(使用可选部分),但问题是输入序列“.-”对于Java-8也是可以的。
嗯,这里提到的这些小缺点是为了完整性。最终几乎完美的解决方案将在Java-8中使用:
String input = "2017-02.-31";
DateTimeFormatter dtf =
DateTimeFormatter.ofPattern("yyyy[.][-]MM[.][-]dd").withResolverStyle(
ResolverStyle.STRICT // smart mode truncates to Feb 28!
);
ParsePosition pos = new ParsePosition(0);
TemporalAccessor ta = dtf.parseUnresolved(input, pos); // step 1
LocalDate date = null;
if (pos.getErrorIndex() == -1 && pos.getIndex() == input.length()) {
try {
date = LocalDate.parse(input, dtf); // step 2
} catch (DateTimeException dte) {
dte.printStackTrace(); // in strict mode (see resolver style above)
}
}
System.out.println(date); // 2017-02-28 in smart mode
重要提示:
ta
的结果parseUnresolved()
不能用作中间结果。所以这个两步法对于性能来说也不是那么好。我没有对正常的一步法进行基准测试,但希望新API(S. Colebourne)的主要作者可能已经完成了它,也可以在他自己的javadoc中查看他的解决方案。或多或少是一种尽可能避免异常流动的hackish解决方法。<强>替代强>
如果您寻找替代方案而不是SimpleDateFormat
,那么您可能还会发现我的库backport很有趣。它支持真正的OR逻辑并尽可能地避免异常流逻辑(仅在一步中高度调整解析)。例如:
String input = "2017-02-31";
ParseLog plog = new ParseLog();
PlainDate date =
ChronoFormatter.ofDatePattern(
"uuuu-MM-dd|uuuu.MM.dd", PatternType.CLDR, Locale.ROOT)
.parse(input, plog); // uses smart mode by default and rejects feb 31 in this mode
if (plog.isError()) {
System.out.println(plog.getErrorMessage());
} else {
System.out.println(date);
}
注意:
LocalDate
date.toTemporalAccessor()
Attributes.LENIENCY
会削弱验证答案 2 :(得分:1)
如果您有一个已知的格式列表,则可以创建线程安全org.joda.time.format.DateTimeFormatter
的实例,将它们放入列表中,然后迭代直到其中一个可以成功解析日期。这些解析器的内存消耗可以忽略不计,一旦找到匹配的格式,就可以使用生成的日期对象。
这也有利于比正则表达式更具可读性。请注意将正则表达式用于可能含糊不清的格式,例如mm-dd-yyyy
与dd-mm-yyyy
。
答案 3 :(得分:1)
您可以尝试Pojava DateTime。它启发式地分析日期和时间,而不是匹配格式,并支持各种语言(例如月份名称)和格式。见http://pojava.org/howto/datetime.html
典型用法依赖于系统的区域设置来解决格式是m / d / y与d / m / y的模糊性,因此默认情况下您通常只需要:DateTime dt1=new DateTime("01/02/2003");
如果您的服务器正在处理从多个区域设置派生的日期,并且需要解释&#34; 01/02/2003&#34; as&#34; 1月2日&#34;如果来自一个地区,并且&#34; 2月1日和#34;如果来自不同的语言环境,则可以指定从外部语言环境解析时要使用的配置对象。
DateTimeConfigBuilder builder = DateTimeConfigBuilder.newInstance();
builder.setDmyOrder(false);
builder.setInputTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
builder.setOutputTimeZone(TimeZone.getTimeZone("America/Porto_Velho"));
IDateTimeConfig config=DateTimeConfig.fromBuilder(builder);
DateTime dt1=new DateTime("01/02/2003 13:30", config)