我尝试使用DateTimeFormatterBuilder创建一个强大的解决方案来支持不同的日期格式。 我希望能够仅通过了解日/月/年/小时/分钟/秒/秒的顺序来解析用户提供的几乎任何日期字符串。
我想到了两种解决方案:
使用正则表达式将所有已知的分隔符替换为特定的分隔符(例如“?”),并使用DateTimeFormatterBuilder创建自定义日期格式。
基本上是同一件事,但是我将提供“已知”定界符的列表,并将它们作为可选的附加到theDateTimeFormatterBuilder
注意-我们遇到的问题之一是日期时间成分之间的空格不一致(例如:dd_MM YYYY或dd _____ MM__YYYY)
注2 性能至关重要
我的问题:有什么办法可以避免所有这些情况并使用一些内置功能 忽略年,月,日等之间的文本的方法(类似可选)
解决方案1(为简单起见,假设订单为年-月-年):
private static final String[] DELIMITTER= {"?"};
public static void main(String[] args) {
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder().appendValue(ChronoField.DAY_OF_MONTH);
appendDelims(builder);
builder.appendValueReduced(ChronoField.MONTH_OF_YEAR,1,2,1);
appendDelims(builder);
builder.appendValueReduced(ChronoField.YEAR, 2, 4, LocalDate.ofEpochDay(0));
DateTimeFormatter dateTimeFormatter = builder.toFormatter();
System.out.println("dt = " + LocalDate.parse("23 2,,,,05".replaceAll("\\s+|-+|,+","?"),dateTimeFormatter));
System.out.println("dt2 = " + LocalDate.parse("09-----2 2015".replaceAll("\\s+|-+|,+","?"), dateTimeFormatter));
}
private static void appendDelims(DateTimeFormatterBuilder dtb){
for(String d : DELIMITTER) {
dtb.appendOptional(DateTimeFormatter.ofPattern(d));
}
}
输出- dt = 2005-02-23 dt2 = 2015-02-09
解决方案2-
private static final String[] DELIMITTER= {"?","-"," "," "};
public static void main(String[] args) {
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder().appendValue(ChronoField.DAY_OF_MONTH);
appendDelims(builder);
builder.appendValueReduced(ChronoField.MONTH_OF_YEAR,1,2,1);
appendDelims(builder);
builder.appendValueReduced(ChronoField.YEAR, 2, 4, LocalDate.ofEpochDay(0));
DateTimeFormatter dateTimeFormatter = builder.toFormatter();
System.out.println("dt = " + LocalDate.parse("23?2 05",dateTimeFormatter));
System.out.println("dt2 = " + LocalDate.parse("9?2-2015", dateTimeFormatter));
}
private static void appendDelims(DateTimeFormatterBuilder dtb){
for(String d : DELIMITTER) {
dtb.appendOptional(DateTimeFormatter.ofPattern(d));
}
}
输出- dt = 2005-02-23 dt2 = 2015-02-09
答案 0 :(得分:0)
没有任何合理的方法来避免使用解决方案1或解决方案2。DateTimeFormatter
和DateTimeFormatterBuilder
中唯一可以忽略不同定界符的机制是使部分格式可选的机制:
appendOptional
您已经在使用optionalStart
和optionalEnd
[
和]
。当然还有其他可能性,例如从头开始编写自己的解析器,但是对于您已经在做的事情,我真的不推荐。
在解决方案1中,由于您要替换定界符,因此我认为您不需要调用appendDelims
。以下格式化程序适用于您的两个示例日期字符串:
DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder().appendValue(ChronoField.DAY_OF_MONTH)
.appendPattern("?M?")
.appendValueReduced(ChronoField.YEAR, 2, 4, LocalDate.EPOCH)
.toFormatter();
PS一个月不使用appendValueReduced
,只是令人困惑。使用单个模式字母M
来匹配1或2位数字的月份编号,例如8
,08
或11
。