使用DateTimeFormatterBuilder创建自定义日期格式,并忽略“计时”字段之间的原始文本

时间:2018-11-19 07:24:51

标签: java datetime datetime-format

我尝试使用DateTimeFormatterBuilder创建一个强大的解决方案来支持不同的日期格式。 我希望能够仅通过了解日/月/年/小时/分钟/秒/秒的顺序来解析用户提供的几乎任何日期字符串。

我想到了两种解决方案:

  1. 使用正则表达式将所有已知的分隔符替换为特定的分隔符(例如“?”),并使用DateTimeFormatterBuilder创建自定义日期格式。

  2. 基本上是同一件事,但是我将提供“已知”定界符的列表,并将它们作为可选的附加到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

1 个答案:

答案 0 :(得分:0)

没有任何合理的方法来避免使用解决方案1或解决方案2。DateTimeFormatterDateTimeFormatterBuilder中唯一可以忽略不同定界符的机制是使部分格式可选的机制:

  1. appendOptional您已经在使用
  2. optionalStartoptionalEnd
  3. 格式模式中的方括号[]

当然还有其他可能性,例如从头开始编写自己的解析器,但是对于您已经在做的事情,我真的不推荐。

在解决方案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位数字的月份编号,例如80811