mag*_*lla 1 java validation parsing date
最近开始使用WEB UI。并且遇到了日期字符串解析/验证的问题。“dd-mm-yyyy”我发现的一些方法是:
匹配 - 不完整的验证,不灵活。
(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])
有一个帖子,有人建议用可能的日期字符串预初始化 Set - 快速,有效,但也不灵活且消耗内存
有没有更简单的东西,也许在公共库中可用?
请不要建议 SimpleDateFormat :)
UPDATE 对Java 8正确答案是/sf/answers/3015320101/
前言:
如果您不关心细节,那么接受的答案建议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”(二月有 31 天???)。
Java-8 解析机制
DateTimeFormatter
然而,Java-8 类可以仅通过解析使这种不存在的日期无效。为了深入细节,我们必须区分句法验证和日历验证。第一种语法验证由方法parseUnresolved() 执行。
解析是作为两阶段操作实现的。首先,使用格式化程序定义的布局解析文本,生成字段到值的映射、ZoneId 和 Chronology。其次,通过验证、组合和简化各个字段为更有用的字段来解析解析的数据。此方法执行解析阶段,但不执行解析阶段。
这种方法的主要优点是不使用异常流,这使得这种解析速度很快。但是,解析的第二步使用了异常流,另见方法的javadocparse(CharSequence, ParsePosition)
。
相比之下,如果发生错误,此方法将抛出 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
Run Code Online (Sandbox Code Playgroud)
重要的:
ta
中方法的结果parseUnresolved()
不能用作中间结果。所以这种两步法对性能也不是太好。我没有将它与正常的 1-step-approach 进行基准测试,但希望新 API 的主要作者(S. Colebourne)可能已经做到了,另请参阅他自己的Threeten-extra-library 中的解决方案进行比较。或多或少是一种黑客解决方法,以尽可能避免异常流。选择
如果您寻找替代方案而不是 for SimpleDateFormat
,那么您可能还会发现我的库Time4J很有趣。它支持真正的 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);
}
Run Code Online (Sandbox Code Playgroud)
笔记:
LocalDate
viadate.toTemporalAccessor()
Attributes.LENIENCY
会削弱验证 归档时间: |
|
查看次数: |
7109 次 |
最近记录: |