1. 简介
在Java应用中处理日期时间是常见任务。无论是解析输入、格式化输出,还是程序内部操作日期时间,Java都提供了强大的工具高效处理这些场景。我们经常需要从一个日期时间字符串中提取日期和时间部分,以便进行后续处理。
本文将探讨从输入字符串中分别提取日期和时间的多种方法。
2. 理解问题
处理日期时间字符串时,最关键的一步是确定特定的格式。没有标准格式,正确处理输入字符串几乎不可能。因此,格式需要事先约定。
本教程中,我们定义一个示例日期时间字符串:
String datetime = "2024-07-04 11:15:24"
我们将使用格式 yyyy-MM-dd HH:mm:ss 作为预期标准。此外,我们还将支持带毫秒的格式 yyyy-MM-dd HH:mm:ss.SSS。
给定这个输入字符串,我们需要将其拆分为两个字符串:2024-07-04 和 11:15:24。
3. 使用 split()
我们可以通过空格分割输入字符串,从而分离日期和时间部分。来看实现:
@Test
void givenDateTimeString_whenUsingSplit_thenGetDateAndTimeParts() {
String dateTimeStr = "2024-07-04 11:15:24";
String[] split = dateTimeStr.split("\\s");
assertEquals(2, split.length);
assertEquals("2024-07-04", split[0]);
assertEquals("11:15:24", split[1]);
}
这段代码将字符串分割成日期和时间组件。但要注意,即使字符串无效,这段代码也会进行分割而不会提示任何错误。因此,可能存在更优雅的解决方案。
另一方面,只要日期和时间由空格分隔,这种方法就能分割任何输入字符串,使其适用于多种格式而无需指定确切模式。
再看另一个例子:
String dateTimeStr = "2024/07/04 11:15:24.233";
String[] split = dateTimeStr.split("\\s");
assertEquals(2, split.length);
assertEquals("2024/07/04", split[0]);
assertEquals("11:15:24.233", split[1]);
上例中,日期时间不符合预期模式,但由于日期和时间部分由空格分隔,我们仍可使用此方法。
然而,如果字符串中有多个空格,分割就会出错。这种情况下,我们可以使用带limit参数的*split()*:
String dateTimeStr = "8/29/2011 11:16:12 AM";
String[] split = dateTimeStr.split("\\s", 2);
assertEquals(2, split.length);
assertEquals("8/29/2011", split[0]);
assertEquals("11:16:12 AM", split[1]);
这里,我们使用limit为2的*split()*函数。这确保字符串在第一个空格处分割,剩余部分作为第二部分返回。即使日期时间字符串中包含AM/PM等额外标记,此方法也能让我们分别提取日期和时间。
4. 使用 DateTimeFormatter
另一种分离日期和时间组件的方法是使用java.time API。我们可以使用DateTimeFormatter将字符串解析为LocalDateTime对象,然后通过该对象的方法分离日期和时间组件。
看个例子:
String dateTimeStr = "2024-07-04 11:15:24";
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.ENGLISH);
DateTimeFormatter timeFormat = DateTimeFormatter.ofPattern("HH:mm:ss", Locale.ENGLISH);
LocalDateTime dateTime = LocalDateTime.parse(dateTimeStr, format);
assertEquals("2024-07-04", dateTime.toLocalDate().format(dateFormat));
assertEquals("11:15:24", dateTime.toLocalTime().format(timeFormat));
这里,我们为输入字符串的预期模式创建了DateTimeFormatter实例。然后使用该格式化器将字符串解析为LocalDateTime。之后,我们可以使用其方法获取日期和时间组件。
*与split()函数相比,这种方法的优点是能验证日期时间字符串的有效性**。但缺点是必须事先知道确切模式,而split()*方法可以在不知道确切格式的情况下处理多种格式。
我们来看看如何改进此实现以支持多种格式同时验证日期时间。我们可以使用DateTimeFormatterBuilder定义多种格式。示例如下:
DateTimeFormatter format1 = DateTimeFormatter.ofPattern("dd-MM-yyyy'T'HH:mm:ss.SSS", Locale.ENGLISH);
DateTimeFormatter format2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
DateTimeFormatterBuilder dateTimeFormatterBuilder = new DateTimeFormatterBuilder();
DateTimeFormatter multiFormatter = dateTimeFormatterBuilder
.appendOptional(format1)
.appendOptional(format2)
.toFormatter(Locale.ENGLISH);
// case 1
LocalDateTime dateTime1 = LocalDateTime.parse("2024-07-04 11:15:24", multiFormatter);
String date1 = dateTime1.toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
String time1 = dateTime1.toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
assertEquals("2024-07-04", date1);
assertEquals("11:15:24", time1);
// case 2
LocalDateTime dateTime2 = LocalDateTime.parse("04-07-2024T11:15:24.123", multiFormatter);
String date2 = dateTime2.toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
String time2 = dateTime2.toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS"));
assertEquals("2024-07-04", date2);
assertEquals("11:15:24.123", time2);
上述代码中,我们利用DateTimeFormatterBuilder通过appendOptional()方法定义了多种支持的格式。然后调用toFormatter()方法获取DateTimeFormatter实例。接着,我们使用这个格式化器解析输入字符串。这种方法可以轻松解析三种不同的格式。
但缺点是,在转换回分离的日期和时间字符串时,必须显式提供确切格式。
5. 使用正则表达式
我们还可以使用正则表达式分别提取日期和时间组件。看一个示例代码:
String dateTimeStr = "2024-07-04 11:15:24.123";
Pattern pattern = Pattern.compile("(\\d{4}-\\d{2}-\\d{2})\\s(\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?)");
Matcher matcher = pattern.matcher(dateTimeStr);
assertTrue(matcher.matches());
assertEquals("2024-07-04", matcher.group(1));
assertEquals("11:15:24.123", matcher.group(2));
这里,我们使用正则表达式匹配并提取字符串中的日期和时间组件。这种方法在处理各种格式时提供了灵活性,但需要精心设计正则表达式。
6. 总结
本文探讨了在Java中从日期时间字符串分离日期和时间组件的多种方法。我们介绍了简单的字符串分割、使用DateTimeFormatter以及使用DateTimeFormatterBuilder处理多种格式,还讨论了正则表达式的使用。每种方法都有优缺点,选择取决于应用的需求和约束。
一如既往,本文中使用的示例代码可在GitHub上获取。