1. 概述
在某些情况下,我们需要解析可能以多种格式提供的日期字符串,如 'yyyy/MM/dd'、'yyyy-MM-dd' 或 'dd-MM-yyyy'。本教程将展示我们解析不同日期模式的一些选项。首先,我们将尝试使用标准Java库来解决解析问题:SimpleDateFormat
和 DateTimeFormatterBuilder
。然后,我们将研究第三方库 Apache Commons 的 DateUtils
和 Joda Time。
2. 使用 SimpleDateFormat
首先,我们使用 Java 的 SimpleDateFormat
来解析具有多个格式的日期。首先,我们定义一个可能的日期格式列表,并遍历所有格式,直到找到匹配我们的字符串的格式。一旦匹配,我们返回一个 java.util.Date
。如果没有匹配,则返回 null
:
public static Date parseDate(String dateString, List<String> formatStrings) {
for (String formatString : formatStrings) {
try {
return new SimpleDateFormat(formatString).parse(dateString);
} catch (ParseException e) {
}
}
return null;
}
这种方法有其优缺点。优点是无需外部库,实现简单直接。然而,我们需要提前知道所有可能的匹配日期格式,并且没有日期验证功能。我们可以解析匹配模式但仍然无效的日期,例如,解析 '2022-40-40',SimpleDateFormater
将返回 '2025-05-10'。
让我们看一个例子,说明解析这个无效日期会得到意外的结果:
@Test
public void whenInvalidInput_thenGettingUnexpectedResult() {
SimpleParseDate simpleParseDate = new SimpleParseDate();
String date = "2022-40-40";
assertEquals(
"Sat May 10 00:00:00 EEST 2025",
simpleParseDate.parseDate(date, Arrays.asList("MM/dd/yyyy", "dd.MM.yyyy", "yyyy-MM-dd"))
);
}
3. 使用 DateTimeFormatterBuilder
SimpleDateFormat
是 Java 的原始实现,而 java.util.Date
的许多方法已过时,因此更好的选择是使用 DateTimeFormatterBuilder
。与 SimpleDateFormatter
不同,DateTimeFormatterBuilder
可以接收多个日期模式,并尝试解析给定日期的所有模式。如果有匹配的模式,它将返回解析后的日期,否则将抛出 DateTimeParseException
:
public static LocalDate parseDate(String date) {
DateTimeFormatterBuilder dateTimeFormatterBuilder = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ofPattern("[MM/dd/yyyy]" + "[dd-MM-yyyy]" + "[yyyy-MM-dd]"));
DateTimeFormatter dateTimeFormatter = dateTimeFormatterBuilder.toFormatter();
return LocalDate.parse(date, dateTimeFormatter);
}
让我们使用此格式器解析一些日期:
@Test
public void whenInvalidDate_thenAssertThrows() {
assertEquals(
java.time.LocalDate.parse("2022-12-04"),
simpleDateTimeFormater.parseDate("2022-12-04")
);
assertThrows(DateTimeParseException.class, () -> simpleDateTimeFormater.parseDate("2022-13-04"));
}
4. Apache Commons DateUtils
另一个选择是使用 Apache Commons 库,它提供了 DateUtils
辅助工具。首先,我们需要包含 Apache Commons Lang 的依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
DateUtils
的工作方式类似于 DateTimeFormatterBuilder
。我们可以向其提供几个日期格式,如果其中一个格式匹配要解析的字符串,它将解析日期:
DateUtils.parseDateStrictly("2022-12-29",new String[]{"yyyy/MM/dd", "dd/MM/yyyy", "yyyy-MM-dd"});
让我们使用 DateUtils
解析无效和有效的日期:
@Test
public void whenDateIsCorrect_thenParseCorrect() {
SimpleDateUtils simpleDateUtils = new SimpleDateUtils();
assertNull(simpleDateUtils.parseDate("53/10/2014"));
assertEquals("Wed Sep 10 00:00:00 UTC 2014", simpleDateUtils.parseDate("10/09/2014").toString());
}
5. Joda Time
另一个第三方选项是使用 Joda Time 库。值得注意的是,在 Java SE 8 之前,Joda Time 是 Java 的事实上的日期和时间库。首先,我们需要添加其依赖:
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.12.5</version>
</dependency>
让我们定义 DateTimeFormat
可用的模式:
public static LocalDate parseDate(String date) {
List<String> patternList = Arrays.asList("MM/dd/yyyy", "dd.MM.yyyy", "yyyy-MM-dd");
for (String pattern : patternList) {
try {
return DateTimeFormat.forPattern(pattern).parseLocalDate(date);
} catch (IllegalFieldValueException e) {
}
}
return null;
}
现在,让我们使用 Joda Time 编写一个测试,解析一些日期:
@Test
public void whenDateIsCorrect_thenResultCorrect() {
SimpleDateTimeFormat simpleDateUtils = new SimpleDateTimeFormat();
assertNull(simpleDateUtils.parseDate("53/10/2014"));
assertEquals(LocalDate.parse("2014-10-10"), simpleDateUtils.parseDate("2014-10-10"));
}
6. 总结
在这篇文章中,我们了解了使用标准Java库解析具有多个格式的日期的一些选项。此外,我们还通过第三方库 Apache Commons Lang 和 Joda Time 解决了日期解析问题。
如往常一样,您可以在 GitHub 上找到这些示例。