java.time
让我们看看java.time框架是否可以提供帮助。
关于 java.time
Java 8 和后来的 java.time 框架取代了麻烦的旧 java.util.Date/。日历类。新类的灵感来自非常成功的Joda-Time框架,旨在作为其继任者,在概念上相似,但重新构建。由 JSR 310 定义。由ThreeTen-Extra项目扩展。请参阅教程。
LocalDate
与旧类不同,java.time 提供 LocalDate
类来表示仅日期值,没有时间或时区。
法语缩写
看看java.time中的格式化程序对en Français中的缩写月份名称的期望。
我们可以循环月
枚举以获取月列表。此枚举提供 getDisplayName
方法,用于生成月份的本地化名称。此代码演示该方法生成与 java.time 格式化程序相同的输出。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "dd-MMM-yyyy" ).withLocale ( Locale.FRENCH );
for ( Month month : Month.values () ) {
LocalDate localDate = LocalDate.of ( 2015 , month.getValue () , 1 );
String output = formatter.format ( localDate );
String displayName = month.getDisplayName ( TextStyle.SHORT , Locale.FRENCH );
System.out.println ( "output: " + output + " | displayName: " + displayName );// System.out.println ( "input: " + input + " → " + localDate + " → " + output );
}
output: 01-janv.-2015 | displayName: janv.
output: 01-févr.-2015 | displayName: févr.
output: 01-mars-2015 | displayName: mars
output: 01-avr.-2015 | displayName: avr.
output: 01-mai-2015 | displayName: mai
output: 01-juin-2015 | displayName: juin
output: 01-juil.-2015 | displayName: juil.
output: 01-août-2015 | displayName: août
output: 01-sept.-2015 | displayName: sept.
output: 01-oct.-2015 | displayName: oct.
output: 01-nov.-2015 | displayName: nov.
output: 01-déc.-2015 | displayName: déc.
我们发现 3 个和 4 个字母的拼写混合。较长的名称缩写为四个字符加一个句点(句号)。四个月的名称足够短,无需缩写即可使用:、、、、。mars
mai
juin
août
因此,正如其他答案中所讨论的,没有简单的解决方案。
修复数据源
我的第一个建议是修复数据源。该来源显然没有遵循适当的法语缩写规则。耶鲁同意Java 8对法语的理解。顺便说一句,如果修复您的数据源,我强烈建议使用四位数年份作为两个年份,这会导致无休止的混乱和歧义。
修复输入
当然,来源可能不受您的控制/影响。在这种情况下,与其他答案一样,您可能需要进行暴力替换,而不是尝试任何聪明。另一方面,如果输入的唯一问题是只是缺少句点(句号),那么您可以使用枚举进行软编码,而不是对不正确的值进行硬编码。Month
我会进行初始解析尝试。DateTimeParseException 的
陷阱,在尝试修复之前。如果引发异常,则修复输入。
若要修复输入,请尝试通过循环可能的枚举实例集来尝试一年中的每个月。对于每个月,获取其缩写名称。从该缩写中去掉句点(句号),以匹配我们怀疑不正确的传入值。测试以查看这是否确实与输入匹配。如果没有,请转到下个月。
当我们获得匹配项时,修复输入以正确缩写区域设置的规则(在我们的例子中为法语规则)。然后解析固定输入。这将是我们的第二次解析尝试,因为我们进行了初始尝试。如果第二次尝试失败,则此处所示,存在非常错误的情况。但通常情况下,第二次解析尝试会成功,我们可以从枚举的循环中解脱出来。FIXME:
for
Month
最后,您可以通过测试结果是否仍然是最初设置的虚假标志值(LocalDate.MIN
)来验证成功。
String input = "09-oct-08"; // Last two digits are Year.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "dd-MMM-yy" ).withLocale ( Locale.FRENCH );
LocalDate localDate = LocalDate.MIN; // Some folks prefer a bogus default value as a success/failure flag rather than using a NULL.
try {
localDate = LocalDate.parse ( input , formatter );
} catch ( DateTimeParseException e ) {
// Look for any month name abbreviation improperly missing the period (FULL STOP).
for ( Month month : Month.values () ) {
String abbreviation = month.getDisplayName ( TextStyle.SHORT , Locale.FRENCH );
String abbreviationWithoutFullStop = abbreviation.replace ( "." , "" ); // Get short abbreviation, but drop any period (FULL STOP).
String proper = "-" + abbreviation + "-";
String improper = "-" + abbreviationWithoutFullStop + "-";
if ( input.contains ( improper ) ) {
String inputFixed = input.replace ( improper , proper );
try {
localDate = LocalDate.parse ( inputFixed , formatter );
} catch ( DateTimeParseException e2 ) {
// FIXME: Handle this error. We expected this second parse attempt to succeed.
}
break; // Bail-out of the loop as we got a hit, matching input with a particular improper value.
}
}
}
Boolean success = ! ( localDate.equals ( LocalDate.MIN ) );
String formatted = formatter.format ( localDate );;
String outputImproper = formatted.replace ( "." , "" ); // Drop any period (FULL STOP).
转储到控制台。
System.out.println ( "success: " + success + ". input: " + input + " → localDate: " + localDate + " → formatted: " + formatted + " → outputImproper: " + outputImproper );
成功:没错。输入: 09-oct-08 → 本地日期: 2008-10-09 → 格式化: 09-oct.-08 →输出更新: 09-oct-08