DateTimeFormatter无法解析德语中没有前导零的日期

我们的客户今天发现了一个有趣的错 考虑以下方法:

final DateTimeFormatter englishFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(Locale.ENGLISH); System.out.println(LocalDate.parse("04/01/17", englishFormatter)); System.out.println(LocalDate.parse("4/1/17", englishFormatter)); final DateTimeFormatter germanFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(Locale.GERMAN); System.out.println(LocalDate.parse("01.04.17", germanFormatter)); System.out.println(LocalDate.parse("1.4.17", germanFormatter)); 

(如果您不知道,这些确实是英语和德语的正确日期。我甚至会说它们是相同的日期[2017年4月1日]。请花点时间考虑一下您认为该应用程序应该返回的内容。 )

它返回的是以下内容:

 Exception in thread "main" java.time.format.DateTimeParseException: Text '1.4.17' could not be parsed at index 0 at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949) at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851) at java.time.LocalDate.parse(LocalDate.java:400) at Main.main(Main.java:20) 

英语日期格式使用和不使用前导零。 德语格式仅适用于前导零。

我似乎无法找到一个属性来更改此行为以正常工作。

如何让DateTimeFormatter没有前导零的情况下理解德语日期?

注意:我们的应用程序支持多种语言环境,因此使用特定的DateTimeFormatter (如DateTimeFormatter.ofPattern("dMyy") )是完全DateTimeFormatter.ofPattern("dMyy")的,特别是因为我们要解析默认的日期格式。

我尝试了相反的方法:使用本地化格式化程序格式化日期。

  LocalDate testDate = LocalDate.of(2017, Month.APRIL, 1); final DateTimeFormatter englishFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT) .withLocale(Locale.ENGLISH); System.out.println("English: " + testDate.format(englishFormatter)); final DateTimeFormatter germanFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT) .withLocale(Locale.GERMAN); System.out.println("German: " + testDate.format(germanFormatter)); 

我有

 English: 4/1/17 German: 01.04.17 

所以很明显Java认为标准的德语日期格式使用前导零。 如果您确定这是错误的,您可以考虑向Oracle提交错误。

为了避免你不喜欢的行为,使用多个语言环境我恐怕你需要某种黑客攻击。 我能想到的最好的黑客是以下内容。 它不漂亮。 有用。

 private static final Map STEFFI_S_LOCALIZED_FORMATTERS = createSteffiSFormatters(); private static Map createSteffiSFormatters() { Map formatters = new HashMap<>(2); formatters.put(Locale.GERMAN, DateTimeFormatter.ofPattern("dMuu")); return formatters; } public static DateTimeFormatter getLocalizedFormatter(Locale formattingLocale) { DateTimeFormatter localizedFormatter = STEFFI_S_LOCALIZED_FORMATTERS.get(formattingLocale); if (localizedFormatter == null) { localizedFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT) .withLocale(formattingLocale); } return localizedFormatter; } 

现在你可以这样做:

  final DateTimeFormatter englishFormatter = getLocalizedFormatter(Locale.ENGLISH); System.out.println(LocalDate.parse("04/01/17", englishFormatter)); System.out.println(LocalDate.parse("4/1/17", englishFormatter)); final DateTimeFormatter germanFormatter = getLocalizedFormatter(Locale.GERMAN); System.out.println(LocalDate.parse("01.04.17", germanFormatter)); System.out.println(LocalDate.parse("1.4.17", germanFormatter)); 

这打印:

 2017-04-01 2017-04-01 2017-04-01 2017-04-01 

一种解决方案是捕获DateTimeParseException,然后使用修改/缩减日期模式再次尝试。

 import java.text.Format; import java.time.LocalDate; import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; import java.time.format.FormatStyle; import java.util.ListResourceBundle; import java.util.Locale; public class Demo { public static void main(String[] args) { Locale[] locales = {Locale.ENGLISH, Locale.GERMAN}; for (Locale locale : locales) { DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(locale); String [] englishDates = {"01/04/17","1/4/17"}; String [] germanDates = {"01.04.17","1.4.17"}; String datePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.SHORT,null, IsoChronology.INSTANCE, locale); System.out.println("Locale " + locale.getDisplayName() + ": Default Date Pattern (short): " + datePattern); String[] dates = null; if (locale == Locale.ENGLISH) dates = englishDates; else dates = germanDates; for (String date : dates) { try { System.out.printf(" " + date + " -> "); System.out.println(LocalDate.parse(date, formatter)); } catch (DateTimeParseException e) { System.out.println("Error!"); // Try alternate pattern datePattern = datePattern.replace("dd", "d").replace("MM", "M"); System.out.println(" Modified Date Pattern (short): " + datePattern); // Allow single digits in day and month DateTimeFormatter modifiedFormatter = DateTimeFormatter.ofPattern(datePattern); System.out.println(" " + date + " -> " + LocalDate.parse(date, modifiedFormatter)); // OK } } } } } 

这给出了:

 Locale English: Default Date Pattern (short): M/d/yy 01/04/17 -> 2017-01-04 1/4/17 -> 2017-01-04 Locale German: Default Date Pattern (short): dd.MM.yy 01.04.17 -> 2017-04-01 1.4.17 -> Error! Modified Date Pattern (short): dMyy 1.4.17 -> 2017-04-01