尽可能动态地(许多不同的格式)从 .csv 文件中解析日期或日期时间字符串?
Parsing Date or DateTime Strings out of a .csv file as dynamically (many different formats) as possible?
我需要一些帮助,以便能够尽可能 dynamically/flexible 从 .csv 文件中解析出字符串数据,这意味着用户可以输入一堆不同类型的格式(即我想处理dd-MMM-yyyy
以及 yyyy-MM-dd
和更多(如果可能的话)日期或日期时间,我应该能够在不抛出异常或崩溃的情况下进行解析。 .csv 文件的 date/datetime 字段的当前格式是 dd-MMM-yyyy
,类似于 30-Apr-2020
。 当然,时间可以添加并且是可选的(如模式所示使用[]括号表示法,因此将是30-Apr-2020 23:59:59
)。我已经这样设置了 date/datetime 列的解析:
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
fails但是 01-May-1999
通过了。
如何处理最不同类型的格式而不导致解析失败? 正如我所说,我实际上并没有生成.csv 文件(即数据工程师)所以我希望这个应用程序尽可能 robust/flexible 并能够解析这种 data/correctly 格式,以便数据可以被使用并相应地写入数据库.我认为我的方法不错,所以我希望不需要大量重写。
您可以使用 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
我需要一些帮助,以便能够尽可能 dynamically/flexible 从 .csv 文件中解析出字符串数据,这意味着用户可以输入一堆不同类型的格式(即我想处理dd-MMM-yyyy
以及 yyyy-MM-dd
和更多(如果可能的话)日期或日期时间,我应该能够在不抛出异常或崩溃的情况下进行解析。 .csv 文件的 date/datetime 字段的当前格式是 dd-MMM-yyyy
,类似于 30-Apr-2020
。 当然,时间可以添加并且是可选的(如模式所示使用[]括号表示法,因此将是30-Apr-2020 23:59:59
)。我已经这样设置了 date/datetime 列的解析:
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
fails但是 01-May-1999
通过了。
如何处理最不同类型的格式而不导致解析失败? 正如我所说,我实际上并没有生成.csv 文件(即数据工程师)所以我希望这个应用程序尽可能 robust/flexible 并能够解析这种 data/correctly 格式,以便数据可以被使用并相应地写入数据库.我认为我的方法不错,所以我希望不需要大量重写。
您可以使用 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