使用 BeanIO 解析 RFC3339 日期字符串 'ss.SSSXX'

Parse RFC3339 Date String 'ss.SSSXX' with BeanIO

我正在尝试像这样解析字符串日期:2021-03-19T13:08:32.58600 在我的模板中使用 BeanIO:

<field name="updatedAt" typeHandler="dateTypeHandler" format="yyyy-MM-dd'T'HH:mm:SSSXX"/>

我收到 Invalid date 错误。

我用 SimpleDateFormat 测试了一些情况,例如,如果我这样做: new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse(text) 有效。

问题出在DateTypeHandlerSupportclass,方法解析验证长度:

    protected Date parseDate(String text) throws TypeConversionException {
        if ("".equals(text))
            return null;

        ParsePosition pp = new ParsePosition(0);
        Date date = getFormat().parse(text, pp);
        if (pp.getErrorIndex() >= 0 || pp.getIndex() != text.length()) {
            throw new TypeConversionException("Invalid date");
        }
        return date;
    }

有什么方法可以在不创建自己的 DateTypeHandler 的情况下解析字符串?

您的字符串的结尾 00 不是有效的 UTC 偏移量。我非常相信它永远不会成为一个。相反,您的字符串为我们提供了带有 5 位小数的秒数,并且不包含偏移量。

很抱歉,您无法解析它。如果 BeanIO 内部使用 SimpleDateFormat(一个臭名昭著的 class 麻烦制造者,幸好早就过时了),那么它就无法正确解析 2021-03-19T13:08:32.58600SimpleDateFormat 只支持秒的三位小数,并将 .58600 解析为 58600 毫秒,即 58.6 秒(正确)。请参阅底部相关问题的链接。

此外,您的字符串不符合 RFC-3339。根据 RFC-3339,时间戳必须包含一个 time-offset,它必须是 "Z" / time-numoffset 之一,其中 time-numoffset("+" / "-") time-hour ":" time-minute。因此,有效偏移量的示例包括 Z+00:00+11:00-00:00-11:00。如果您从某处收到该字符串作为 RFC-3339,那么您似乎需要就该格式标准对发布者进行教育。

在 Java 中解析您的字符串很容易。

    String yourString = "2021-03-19T13:08:32.58600";
    LocalDateTime ldt = LocalDateTime.parse(yourString);
    System.out.println(ldt);

输出:

2021-03-19T13:08:32.586

java.time 的 classes 将 ISO 8601 格式的最常见变体解析为默认值,即没有任何格式规范。 RFC-3339 基于 ISO 8601 并与之相比进行了简化。由于您的字符串不包含 UTC 偏移量,我将其解析为 LocalDateTime,其中 class 表示没有时区或 UTC 偏移量的日期和时间。

链接

我知道当前版本 (2.1) 不支持开箱即用的新 java.time 类,但它将在 new BeanIO project 中得到新生.

虽然我们等待新版本开箱即用地支持 java.time,但您可以通过创建自己的 org.beanio.types.TypeHandler 实现来相对轻松地自己实现它,很可能是通过实现 org.beanio.types.ConfigurableTypeHandler.您可以查看 new TemporalAccessorTypeHandler implementation and use it to roll your own for the time being until you can upgrade to the latest version. This discussion 还展示了如何使用此类型处理程序并对其进行配置。

我不会在这里复制 TemporalAccessorTypeHandler 的代码,但您可以这样配置它:

// declare/register your new type handler
<typeHandler name="javaTimeTypeHandler" 
    class="path.to.your.implementation.TemporalAccessorTypeHandler" />


// now use it in your fields
<field name="updatedAt" typeHandler="javaTimeTypeHandler" 
    format="yyyy-MM-dd'T'HH:mm:SSSXX"/>