java - 更漂亮的Multiple DateTimeFormatter?
问题描述
我得到了多个字符串日期来转换为 OffsetDateTime 并且我通过多次尝试和捕获来做到这一点,我想我不会有其他 DateTimeFormatter 可以写。那么,如何让它更漂亮呢?
代码:
public static OffsetDateTime convertStringDateToOffsetDate(String dateStr){
DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").withLocale( Locale.US );
DateTimeFormatter f2 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss").withZone(ZoneId.of("Europe/Paris"));
DateTimeFormatter f3 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX").withZone(ZoneId.of("Europe/Paris"));
DateTimeFormatter f4 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS").withZone(ZoneId.of("Europe/Paris"));
DateTimeFormatter f5 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS").withZone(ZoneId.of("Europe/Paris"));
DateTimeFormatter f6 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX").withZone(ZoneId.of("Europe/Paris"));
OffsetDateTime myDate = null;
try{
myDate = ZonedDateTime.parse(dateStr, f).toOffsetDateTime();
} catch(DateTimeParseException e){
try{
myDate = ZonedDateTime.parse(dateStr, f2).toOffsetDateTime();
} catch (DateTimeParseException ex) {
try{
myDate = ZonedDateTime.parse(dateStr, f3).toOffsetDateTime();
} catch (DateTimeParseException exc) {
try{
myDate = ZonedDateTime.parse(dateStr, f4).toOffsetDateTime();
} catch (DateTimeParseException exce) {
try{
myDate = ZonedDateTime.parse(dateStr, f5).toOffsetDateTime();
} catch(DateTimeParseException excep){
myDate = ZonedDateTime.parse(dateStr, f6).toOffsetDateTime();
}
}
}
}
}
return myDate;
}
解决方案
这是我的尝试。
private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.optionalStart()
.appendOffsetId()
.optionalEnd()
.toFormatter(Locale.ROOT);
private static final ZoneId DEFAULT_ZONE = ZoneId.of("Europe/Paris");
public static OffsetDateTime convertStringDateToOffsetDate(String dateStr) {
TemporalAccessor parsed
= PARSER.parseBest(dateStr, OffsetDateTime::from, LocalDateTime::from);
if (parsed instanceof OffsetDateTime) {
return (OffsetDateTime) parsed;
} else {
return ((LocalDateTime) parsed).atZone(DEFAULT_ZONE).toOffsetDateTime();
}
}
尝试一下:
String[] testStrings = {
"2021-01-01T12:34:56.789-07:00",
"2021-02-01T12:34:56",
"2021-03-01T12:34:56-06:00",
"2021-04-01T12:34:56.987654",
"2021-05-01T12:34:56.789",
"2021-06-01T12:34:56.987654-05:00"
};
for (String testString : testStrings) {
System.out.format("%-32s -> %s%n", testString, convertStringDateToOffsetDate(testString));
}
输出:
2021-01-01T12:34:56.789-07:00 -> 2021-01-01T12:34:56.789-07:00 2021-02-01T12:34:56 -> 2021-02-01T12:34:56+01:00 2021-03-01T12:34:56-06:00 -> 2021-03-01T12:34:56-06:00 2021-04-01T12:34:56.987654 -> 2021-04-01T12:34:56.987654+02:00 2021-05-01T12:34:56.789 -> 2021-05-01T12:34:56.789+02:00 2021-06-01T12:34:56.987654-05:00 -> 2021-06-01T12:34:56.987654-05:00
你发现:
- 它处理您问题中的所有 6 种格式。
- 对于其中包含 UTC 偏移量的字符串,将保留偏移量。对于没有字符串的字符串,假定为 Paris 的正确偏移量(2 月为 +01:00,4 月和 5 月为 +02:00)。
我认为它具有以下优点:
- 我只需要一个格式化程序。
- 我根本没有编写格式模式字符串,只是从内置部件组装了我的格式化程序。
我用来解析的DateTimeFormatter.parseBest
方法将首先尝试创建一个OffsetDateTime
,如果不成功,它将诉诸于创建并返回一个LocalDateTime
. 在后一种情况下,我需要对其进行转换。我的解决方案的缺点是我需要通过一个TemporalAccessor
,这是一个我认为是低级的接口,我们通常不应该在应用程序代码中使用它。
内置DateTimeFOrmatter.ISO_LOCAL_DATE_TIME
已经处理了秒上最多 9 位小数的存在和不存在。因此,通过在我的格式化程序中重用它,我已经处理了没有小数以及 3 位和 6 位小数的情况。
对于其中没有偏移量的字符串,您要求使用欧洲/巴黎时区的一个挑战是,虽然 aDateTimeFormatter
可以有许多默认值,但它不能有默认时区。该withZone
方法为我们提供了一个带有覆盖区域的格式化程序,但这是另一回事。该格式化程序将对格式化或解析的结果强制执行覆盖区域。虽然您的问题尚不清楚,但我假设您不想要这个。
编辑:格式化程序需要语言环境吗?我用于.toFormatter(Locale.ROOT)
从构建器构建格式化程序。从技术上讲,在这种情况下不需要语言环境,因为我的格式化程序不包含任何依赖于语言环境的部分,并且在这个答案的第一个版本中,我没有使用语言环境(toFormatter
而是调用 no-arg 方法)。然而,我倾向于同意 Arvind Kumar Avinash 在评论中的观点:
只是小小的挑剔:请始终使用
Locale
日期时间解析/格式化类型……因为它是一个Locale
敏感类型。它可能与此解决方案中处理的日期时间字符串无关,但我们应该坚持它,就好像它是一条规则一样。
可能只是我自大,并假设读者能够确定格式化程序中没有对语言环境敏感的部分。提供语言环境是更好的习惯(否则至少坚持评论为什么没有)。
推荐阅读
- javascript - 保留文件结构 webpack 5 + angular 12
- html - 如何摆脱链接图像下的这个小链接栏?
- mysql - 从 Windows 10 中 XAMP 中备份的“数据”文件夹中恢复 InnoDB 数据库
- scala - Scala 将数字添加到 Future[List[Try[Option[Int]]]]
- php - mongo db 使用 mongo php 在文档中添加/更新数组
- python - 如何过滤包含字典列表的字典
- r - 在第一个循环-R 处固定一个值
- spring - 如何在 Spring Data MongoRepository 中使用事务?
- python - Django/Python - 将文件从命令输出保存到 ImageField
- javascript - 由于 npm 未导航到不正确的目录,无法运行服务器。并找到 package.jason