Java DateTimeFormatterBuilder未能选择格式

Java DateTimeFormatterBuilder未能选择格式,java,jodatime,datetime-format,datetime-parsing,Java,Jodatime,Datetime Format,Datetime Parsing,我已配置格式化程序: public static final DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder() .append(forPattern("yyyy-MM-dd")) .append(forPattern("MM/dd/yy")) .append(forPattern("MMM dd, yyyy")) .toFormatter(); 并尝

我已配置格式化程序:

public static final DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder()
        .append(forPattern("yyyy-MM-dd"))
        .append(forPattern("MM/dd/yy"))
        .append(forPattern("MMM dd, yyyy"))
        .toFormatter();
并尝试解析字符串
2017-08-29

LocalDate.parse(dt, DATE_FORMATTER).toDateTimeAtStartOfDay().toLocalDateTime()
我得到一个错误:

IllegalArgumentException:无效格式:“2017-08-29”太短

如果我将“yyyy-MM-dd”保留为生成器中的唯一格式,则错误消失


我是否误用了API?如果第一种格式失败,我希望解析器尝试另一种格式。

当您使用
append
方法时,您正在创建一个接受所有三种模式的格式化程序,一个接一个(所有三种都是必需的)

如果要接受三种格式中的任何一种(仅其中一种),则必须使用
appendOptional

DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder()
    .appendOptional(DateTimeFormat.forPattern("yyyy-MM-dd").getParser())
    .appendOptional(DateTimeFormat.forPattern("MM/dd/yy").getParser())
    .appendOptional(DateTimeFormat.forPattern("MMM dd, yyyy").getParser())
    .toFormatter();
现在,您可以解析三种格式中的任意一种:

System.out.println(LocalDate.parse("2017-08-29", DATE_FORMATTER).toDateTimeAtStartOfDay().toLocalDateTime());
System.out.println(LocalDate.parse("08/29/17", DATE_FORMATTER).toDateTimeAtStartOfDay().toLocalDateTime());
System.out.println(LocalDate.parse("Aug 29, 2017", DATE_FORMATTER).toDateTimeAtStartOfDay().toLocalDateTime());
所有上述输出:

2017-08-29T00:00:00.000


只需一个注释:第三个格式化程序使用月短名称(
MMM
),上面的代码假设系统的默认区域设置为英语(创建格式化程序时,默认情况下使用与系统默认区域设置对应的语言)

但是,即使在运行时,也可以在没有通知的情况下进行更改,因此最好在格式化程序中指定
java.util.Locale

示例:如果月份名称始终为英语,只需使用等效的区域设置:

DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder()
    .appendOptional(DateTimeFormat.forPattern("yyyy-MM-dd").getParser())
    .appendOptional(DateTimeFormat.forPattern("MM/dd/yy").getParser())
    .appendOptional(DateTimeFormat.forPattern("MMM dd, yyyy").getParser())
    // use English locale
    .toFormatter().withLocale(Locale.ENGLISH);
只需将区域设置更改为最适合您的需要。更多细节


正如注释中所提醒的,您还可以创建一个解析器数组,并在
DateTimeFormatterBuilder
中使用:

// array with all possible patterns
DateTimeParser[] parsers = new DateTimeParser[] {
    DateTimeFormat.forPattern("yyyy-MM-dd").getParser(),
    DateTimeFormat.forPattern("MM/dd/yy").getParser(),
    DateTimeFormat.forPattern("MMM dd, yyyy").getParser() };

DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder()
    // use array of all possible parsers
    .append(null, parsers)
    // use English locale
    .toFormatter().withLocale(Locale.ENGLISH);
这与前一个的工作方式相同


Java新的日期/时间API Joda Time处于维护模式,正在被新的API所取代,因此我不建议使用它启动新项目。甚至在文章中也提到:“请注意,Joda Time被认为是一个基本上“完成”的项目。没有计划进行重大的增强。如果使用Java SE 8,请迁移到Java.Time(JSR-310)。”

如果您不能(或不想)从Joda Time迁移到新API,可以忽略此部分

如果使用<强> java 8 < />,请考虑使用这更容易


如果您使用的是Java,我不知道Joda时间。您的格式化程序是否希望这三种格式在字符串中彼此紧随其后??只是一个想法。不幸的是,当我看到人们一直在建议一系列可选部分时,我感到有些头痛,尽管目的是实现or语法(标准Java不支持)。依我看,以这种方式使用可选部分仍然是对缺失或功能的一种肮脏的攻击。而乔达时代有这样一件事,在这个问题上看得更好。为了进行比较,请参见打开另一个示例以获得更好的or实现,请参见我的lib@MenoHochschild。事实上,我忘记了Joda Time有一个解析器数组的选项(我有这段代码,只是不记得在编写此答案时)。我已经猜出了答案,非常感谢!
DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder()
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
    .appendOptional(DateTimeFormatter.ofPattern("MM/dd/yy"))
    .appendOptional(DateTimeFormatter.ofPattern("MMM dd, yyyy"))
    // use English locale
    .toFormatter(Locale.ENGLISH);

System.out.println(LocalDate.parse("2017-08-29", DATE_FORMATTER).atStartOfDay());
System.out.println(LocalDate.parse("08/29/17", DATE_FORMATTER).atStartOfDay());
System.out.println(LocalDate.parse("Aug 29, 2017", DATE_FORMATTER).atStartOfDay());
DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("[yyyy-MM-dd][MM/dd/yy][MMM dd, yyyy]", Locale.ENGLISH);