java - 检查给定格式字符串可用于解析的 Temporal 类型
问题描述
我得到了用户输入的一些日期java.time
时间格式字符串,并且需要检查我可以解析该格式数据的时间(在合理的范围内,我现在只支持更简单的情况)。
类似于此表的内容:
输入格式 | 预期答案 |
---|---|
yyyy-MM |
java.time.YearMonth |
MM/dd/yyyy |
java.time.LocalDate |
yyyy:DD |
java.time.LocalDate (因为年数据) |
HH:mm:ss |
java.time.LocalTime |
dd MM yyyy hh:mm:ssV |
java.time.ZonedDateTime |
请记住,日期格式和日期都是由用户输入的,因此这些输入格式只是示例,它们显然可以包含文字(但不是可选部分,这是一种解脱)。
到目前为止,我只能想出这个if
s 的龙卷风作为解决方案:
private static final ZonedDateTime ZDT = ZonedDateTime.of(1990, 10, 26, 14, 40, 59, 123456, ZoneId.of("Europe/Oslo"));
...
String formatted = externalFormatter.format(ZDT);
Class<?> type;
TemporalAccessor parsed = externalFormatter.parse(formatted);
if (parsed.isSupported(YEAR)) {
if (parsed.isSupported(MONTH_OF_YEAR)) {
if (parsed.query(TemporalQueries.localDate()) != null) {
if (parsed.query(TemporalQueries.localTime()) != null) {
if (parsed.query(TemporalQueries.zone()) != null) {
type = ZonedDateTime.class;
}
else if (parsed.query(TemporalQueries.offset()) != null) {
type = OffsetDateTime.class;
}
else {
type = LocalDateTime.class;
}
}
else {
type = LocalDate.class;
}
}
else {
type = YearMonth.class;
}
}
else {
type = Year.class;
}
}
else if (parsed.query(TemporalQueries.localTime()) != null) {
if (parsed.query(TemporalQueries.offset()) != null) {
type = OffsetTime.class;
}
else {
type = LocalTime.class;
}
}
当然,必须有一些更好的方法,至少在一定程度上?我不会限制自己只使用java.time
,我还可以使用 Joda-Time 库(尽管它在技术上处于遗留状态),并且我不会拒绝使用SimpleDateFormat
如果有这样的选项的更简单的代码。
解决方案
DateTimeFormatter::parseBest()
我相信你的话:
请记住,日期格式和日期都是由用户输入的,......</p>
所以我假设我可以同时使用格式模式和输入的日期字符串来查看我能做什么。DateTimeFormatter::parseBest()
是我们需要的方法。
public static TemporalAccessor parse(String formatPattern, String toBeParsed) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatPattern, Locale.ROOT);
return formatter.parseBest(toBeParsed, ZonedDateTime::from,
LocalDate::from, LocalTime::from, YearMonth::from);
}
为了展示上述方法的威力,我使用了以下辅助方法:
public static void demo(String formatPattern, String toBeParsed) {
TemporalAccessor result = parse(formatPattern, toBeParsed);
System.out.format("%-21s %s%n", formatPattern, result.getClass().getName());
}
让我们用你的例子来称呼它:
demo("yyyy-MM", "2017-11");
demo("MM/dd/yyyy", "10/21/2023");
demo("yyyy:DD", "2021:303");
demo("HH:mm:ss", "23:34:45");
demo("dd MM yyyy HH:mm:ssVV", "05 09 2023 14:01:55Europe/Oslo");
我已经更正了最后一个格式模式字符串中的几个错误。输出是:
yyyy-MM java.time.YearMonth MM/dd/yyyy java.time.LocalDate yyyy:DD java.time.LocalDate HH:mm:ss java.time.LocalTime dd MM yyyy HH:mm:ssVV java.time.ZonedDateTime
在TemporalQuery
参数列表中,parseBest()
必须将包含最多信息的类放在首位。或者您喜欢哪些课程,但我假设您想要尽可能多的信息。parseBest()
使用第一个有效的查询。因此,如果您打算支持最后三个中的任何一个,请放在ZonedDateTime
第一个 and和最后一个。Year
Month
DayOfWeek
请记住确定您想要的语言环境。
仅使用格式模式字符串
如果您应该在没有要解析的字符串的情况下完成这个技巧,那么它的复杂性也不会差很多。首先使用您从格式模式字符串构造的格式化程序格式化一些。ZonedDateTime
然后用于parseBest()
解析结果字符串。您必须使用ZonedDateTime
它,因为它是唯一一个包含可能在格式模式字符串中的每个字段的类,因此对于其他一些类,格式可能会中断。另一方面,进入格式化字符串的信息受到模式的限制,因此在大多数情况下,您将无法解析ZonedDateTime
返回。这正是我们想要的:parseBest()
将告诉我们可以解析到哪个类。
public static Class<? extends TemporalAccessor> getParseableType(String formatPattern) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatPattern, Locale.ROOT);
String example = ZonedDateTime.now(ZoneId.systemDefault()).format(formatter);
TemporalAccessor parseableTemporalAccessor = formatter.parseBest(example, ZonedDateTime::from,
LocalDate::from, LocalTime::from, YearMonth::from);
return parseableTemporalAccessor.getClass();
}
文档链接
推荐阅读
- javascript - Tensorflowjs - optimize.minimize 找不到任何变量与损失函数的结果之间的联系
- android - 反应原生 - 获取构建工具文件时出错
- functional-programming - 折叠中间结果列表,而不是 Kotlin 中的最终结果列表
- java - 我是否必须为 Cassandra 中的每次写入打开一个新的数据库连接?
- javascript - 无法插值
- android-nestedscrollview - 在 NestedScrollView 中使用 PagedListAdapter
- ios - 如何设置应用程序委托中可访问的 XCUItest 类的参数
- html - 防止强制字段星号标签换行
- java - 在不使用任何文件路径的情况下解码和解压缩文件
- c# - Caliburn.Micro WPF:如何创建具有依赖项的新 ViewModel?