首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >更漂亮的多重DateTimeFormatter?

更漂亮的多重DateTimeFormatter?
EN

Stack Overflow用户
提问于 2021-04-30 12:52:04
回答 4查看 430关注 0票数 0

我有多个字符串日期要转换为OffsetDateTime,我用多次尝试和捕获完成了,我想我不会有其他的DateTimeFormatter要写了。那么,怎样才能让它更漂亮呢?

代码:

代码语言:javascript
复制
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;
    }
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2021-04-30 13:05:59

代码语言:javascript
复制
public static OffsetDateTime convertStringDateToOffsetDate(String dateStr){
    DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd['T'][ ][HH:mm:ss][.][SSSSSS][SSSSS][SSSS][SSS][XXX][XX][X]").withZone(ZoneId.of("Europe/Paris"));
    return ZonedDateTime.parse(dateStr, f).toOffsetDateTime();
}

这应该可以处理你所有的模式。不需要多个格式化程序或正则表达式。

票数 2
EN

Stack Overflow用户

发布于 2021-04-30 13:07:04

可以使用[]语法将格式字符串的部分声明为可选。这可能会简单地将您带到一个处理所有问题的单一模式。然而,这种设置,其中一个模式有美国地区,但其他没有,该部分将不适合在一个单一的格式字符串。因此,您可以减少格式字符串的#,但可能不会减少到一个字符串。

然后,使用list和helper方法来实现干净的代码:

代码语言:javascript
复制
private static final List<DateTimeFormatter> FORMATS = List.of(
    DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").withLocale( Locale.US ),
    DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.][SSSSSS][XXX]").withZone(ZoneId.of("Europe/Paris")));

public static OffsetDateTime parse(String dateStr) throws DateTimeParseException {
  DateTimeParseException ex = null;

  for (var format : FORMATS) try {
      return ZonedDateTime.parse(dateStr, format).toOffsetDateTime();
  } catch (DateTimeParseException e) {
    ex = e;
  }
  throw ex;
}
票数 2
EN

Stack Overflow用户

发布于 2021-05-01 13:12:26

这是我的刺刀。

代码语言:javascript
复制
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();
    }
}

试试看:

代码语言:javascript
复制
    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: 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偏移量的字符串,
  • 将保留偏移量。对于没有得到字符串的字符串,假定巴黎的偏移量是正确的(2月+01:00,4月和5月+02:00 )。

我相信它有以下优点:

  • 我只需要一个格式化程序。
  • 我根本没有写过格式模式字符串,只是从内置部件组装了我的格式化程序。

我用来解析的DateTimeFormatter.parseBest方法将首先尝试创建一个OffsetDateTime,如果不成功,它将求助于创建和返回一个LocalDateTime。在后一种情况下,我需要转换它。我的解决方案的缺点是我需要通过一个TemporalAccessor,这是一个我认为是低级的接口,我们通常不应该在应用程序代码中使用它。

内置的DateTimeFOrmatter.ISO_LOCAL_DATE_TIME已经在秒内处理多达9个小数点的存在和缺位。因此,通过在我的格式化程序中重用这个,我已经处理了没有小数、3和6个小数的情况。

对于没有偏移量的字符串,您需要使用欧洲/巴黎时区的一个挑战是,虽然DateTimeFormatter可以有许多默认值,但它不能有默认时区。withZone方法为我们提供了一个带有覆盖区域的格式化程序,但这是另一回事。该格式化程序将对格式化或解析的结果强制执行覆盖区域。虽然你的问题还不清楚,但我认为你不想这样。

编辑:格式化程序需要一个区域设置吗?我使用.toFormatter(Locale.ROOT)从构建器构建格式化程序。从技术上讲,在这种情况下,区域设置是不必要的,因为我的格式化程序不包含依赖于区域设置的任何部分,而且在这个答案的第一个版本中,我忽略了区域设置(调用no-arg toFormatter方法)。然而,我倾向于同意Arvind Kumar Avinash的评论:

只是有点挑剔:请始终使用Locale和日期时间解析/格式化类型…。因为它是Locale-sensitive类型。它可能与这个解决方案中处理的日期时间字符串无关,但是我们应该坚持它,就像它是一条规则一样。

这可能只是我的傲慢,并假设读者能够确定格式化程序中没有对环境敏感的部分。提供一个区域设置是更好的习惯(否则,至少在评论中说明为什么没有这样的习惯)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67334271

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档