java - 尽可能动态地(许多不同的格式)从 .csv 文件中解析日期或日期时间字符串?
问题描述
我需要一些帮助,以便能够尽可能动态/灵活地从 .csv 文件中解析出字符串数据,这意味着用户可以输入一堆不同类型的格式(即我想处理dd-MMM-yyyy
,但yyyy-MM-dd
如果可能的话,还可以处理更多)日期或日期时间,我应该能够在不抛出异常或崩溃的情况下进行解析。.csv 文件的日期/日期时间字段的当前格式dd-MMM-yyyy
类似于30-Apr-2020
. 当然, time 可以添加并且是可选的(从模式中可以看出使用 [ ] 括号表示法,所以应该是30-Apr-2020 23:59:59
)。我已经设置了日期/日期时间列的解析,如下所示:
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.appendPattern("dd-MMM-yyyy[[ ]['T']HH:mm:ss]")
.optionalStart()
.appendFraction(ChronoField.MICRO_OF_SECOND, 1, 6, true)
.optionalEnd()
.toFormatter();
TemporalAccessor temporalAccessor = dtf.parseBest(dateString, LocalDateTime::from, LocalDate::from);
if (temporalAccessor instanceof LocalDateTime) {
// process here
} else if (temporalAccessor instanceof LocalDate) {
// process here
}
因此,基本上通过将模式设置为灵活,即"dd-MMM-yyyy[[ ]['T']HH:mm:ss]"
,然后我使用 TemporalAccessor 检查它是日期还是日期时间,并根据需要进行进一步处理。我可以处理许多不同类型的输入,并且不会让应用程序在这里抛出异常并失败。所以我可以消费:
01-Sep-2020 // just date
01-Sep-2099 18:59:59 // datetime
01-Apr-2033 18:59:59.123 // datetime with ms
01-Aug-2057 23:59:59.123456 // date time up to 6 ms decimal pts
但是,如果用户 .csv 包含类似2020-05-30
日期的内容,我认为这是ISO格式标准,它将失败。另外,我现在刚刚注意到的不好的事情是.parseBest()
方法,也失败了,因为它在月份区分大小写,所以像这样的事情01-MAY-1999
失败但01-May-1999
通过了。
如何处理最不同类型的格式而不会解析失败?正如我所说,我实际上并没有生成 .csv 文件(即数据工程师),所以我希望这个应用程序尽可能健壮/灵活,并且能够解析这些数据/正确格式化它,以便可以使用数据并相应地写入数据库。我认为我在这里的方法很不错,所以我希望不需要大量的重写。
解决方案
您可以使用DateTimeFormatterBuilder#parseDefaulting
默认的可选字段,如下例所示:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtfInput = new DateTimeFormatterBuilder()
.parseCaseInsensitive()// For case-insensitive parsing
.appendPattern("[d-M-uuuu[ H[:m[:s]]]]")
.appendPattern("[uuuu-M-d[ H[:m[:s]]]]")
.appendPattern("[uuuu/M/d[ H[:m[:s]]]]")
.appendPattern("[d/M/uuuu[ H[:m[:s]]]]")
.appendPattern("[d-MMM-uuuu[ H[:m[:s[.SSSSSS]]]]]")
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
.toFormatter(Locale.ENGLISH);
String[] arr = {
"10-5-2020",
"2020-5-10",
"10/5/2020",
"2020/5/10",
"10-5-2020 10:20:30",
"10-5-2020 10",
"10-5-2020 10:20",
"10/5/2020 10:20",
"01-May-1999",
"01-MAY-1999",
"01-Aug-2057 23:59:59.123456"
};
for (String dt : arr) {
System.out.println(LocalDateTime.parse(dt, dtfInput));
}
}
}
输出:
2020-05-10T00:00
2020-05-10T00:00
2020-05-10T00:00
2020-05-10T00:00
2020-05-10T10:20:30
2020-05-10T10:00
2020-05-10T10:20
2020-05-10T10:20
1999-05-01T00:00
1999-05-01T00:00
2057-08-01T23:59:59.123456
推荐阅读
- node.js - NodeJs App + AWS EC2 + Nginx + Websocket 配置
- python-3.x - 如何将列表的每个元素分配给另一个列表的每个元素?
- php - 使用 dompdf 生成 PDF 并在分页后的第一个 tr 中获取空白空间
- python - 在 for 循环中输入错误消息时遇到问题。[输入最多 1 个参数,得到 3 个]
- gstreamer - 在 Gstream WebRTCBin 中设置多转服务器
- python - 逐行外加
- p5.js - 在一个形状中混合顶点和曲线顶点?
- owl - 如何使用本体对齐将实例从一个本体转移到另一个(Abox 到 Tbox)
- matlab - AGI STK Matlab 接口
- kubernetes - 在没有 kubectl 的情况下使用 Kubernetes REST API