如何在Java中解析指定时间字符串并生成LocalDateTime?
问题描述
我有以下通过正则从上传数据中提取的时间字符串:
Wednesday, 30 Nov 2022 10:30:00 (UTC) 12/08 (Thu), 10:00 GMT
希望在Java中将这些字符串转换为LocalDateTime类型,期望生成的结果为:
2022/11/30 10:30:00 UTC 2022/12/08 10:00:00 GMT
我编写了对应的处理代码,但调试许久仍未得到预期结果,需要返回Java的LocalDateTime类型,寻求解决方法。
我的代码
@Override public List<LocalDateTime> getTime(String str) { Matcher matcher = regex("(\\d+)\\/(\\d+)\\(\\W\\), \\d+:\\d+-(\\d+):(\\d+)\\s+(\\w+)", str); LocalDateTime date; List<LocalDateTime> list = new ArrayList<>(); int year, month, day, hour, minute, second; ZoneId timezone; year = LocalDateTime.now().getYear(); while(matcher.find()){ month = getMonth(matcher.group(1)); day = Integer.parseInt(matcher.group(2)); hour = Integer.parseInt(matcher.group(3)); minute = Integer.parseInt(matcher.group(4)); second = 0; if(matcher.group(5).equals("KST")) { timezone = ZoneId.of("Asia/Seoul"); } else{ timezone = ZoneId.of(matcher.group(5)); } date = LocalDateTime.of(year, month, day, hour, minute, second); ZonedDateTime time = ZonedDateTime.of(date, timezone); LocalDateTime result = timeZoneConverter(time); list.add(result); } return list; } public static Matcher regex(String regex, String input) { return Pattern.compile(regex, Pattern.MULTILINE).matcher(input); } public static int getMonth(String s) { int result = 0; switch (s) { case "1": case "Jan": result = 1; case "Feb": case "2": result = 2; case "Mar": case "3": result = 3; case "Apr": case "4": result = 4; case "May": case "5": result = 5; case "Jun": case "6": result = 6; case "Jul": case "7": result = 7; case "Aug": case "8": result = 8; case "Sep": case "9": result = 9; case "Oct": case "10": result = 10; case "Nov": case "11": result = 11; case "Dec": case "12": result = 12; } return result; } public static LocalDateTime timeZoneConverter(ZonedDateTime dateTime) { ZonedDateTime resultZonedDateTime = dateTime.withZoneSameInstant(ZoneId.of("Asia/Seoul")); LocalDateTime localDate = LocalDateTime.parse(resultZonedDateTime.toLocalDateTime().toString()); System.out.println("localDate = " + localDate); return localDate; }
问题分析与解决方法
你的代码存在几个核心问题:
- 正则完全不匹配目标格式:
现有正则既没覆盖带英文月份、完整年份的第一种时间格式,还错误加入了不存在的-时间分隔符,导致两种格式都无法匹配。 - getMonth方法逻辑错误:
switch分支未加break,匹配任意月份后都会执行到最后一个case,最终月份恒为12。 - 时区逻辑与需求不符:
你期望保留原时区的时间,但timeZoneConverter强制转成了首尔时区,同时LocalDateTime本身不存储时区信息,若要保留时区需用ZonedDateTime配合单独存储时区标识。 - 手动解析易出错:
手动拆分时间字段的方式繁琐且容易遗漏边界情况,Java自带的DateTimeFormatter能更可靠处理多格式时间解析。
修正后的代码
import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.ChronoField; import java.util.ArrayList; import java.util.List; import java.util.Locale; @Override public List<LocalDateTime> getTime(String str) { List<LocalDateTime> resultList = new ArrayList<>(); // 定义两种时间格式的解析器 DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("EEEE, dd MMM yyyy HH:mm:ss (zzz)", Locale.ENGLISH); DateTimeFormatter formatter2 = new DateTimeFormatterBuilder() .appendPattern("MM/dd (EEE), HH:mm ") .appendZoneText() .parseDefaulting(ChronoField.YEAR, LocalDateTime.now().getYear()) .toFormatter(Locale.ENGLISH); String[] timeStrings = str.split("\\n"); for (String timeStr : timeStrings) { timeStr = timeStr.trim(); if (timeStr.isEmpty()) continue; ZonedDateTime zonedDateTime; try { // 先尝试匹配第一种带完整年份的格式 zonedDateTime = ZonedDateTime.parse(timeStr, formatter1); } catch (Exception e) { // 匹配失败则用第二种格式(自动补充当前年份) zonedDateTime = ZonedDateTime.parse(timeStr, formatter2); } // 将带时区的时间转为LocalDateTime(仅保留时间值,时区需单独存储) resultList.add(zonedDateTime.toLocalDateTime()); // 如需输出期望格式的字符串,可使用以下代码 DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss zzz", Locale.ENGLISH); System.out.println(zonedDateTime.format(outputFormatter)); } return resultList; }
代码说明
- 用
DateTimeFormatter分别适配两种时间格式,无需手动写正则拆分字段,避免解析错误。 - 第二种格式无年份,通过
parseDefaulting自动补充当前年份。 - 先解析为
ZonedDateTime保留时区信息,再按需转为LocalDateTime。 - 可通过指定格式化器直接输出你期望的字符串格式。
内容的提问来源于stack exchange,提问作者sktom2
相关产品推荐
相关产品推荐

