简体   繁体   English

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

[英]Parse RFC3339 Date String 'ss.SSSXX' with BeanIO

I'm trying to parse a String Date like this: 2021-03-19T13:08:32.58600 with BeanIO in my template:我正在尝试解析这样的字符串日期: 2021-03-19T13:08:32.58600 32.58600 在我的模板中使用 BeanIO:

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

And I'm getting Invalid date error.而且我收到Invalid date错误。

I test some cases with SimpleDateFormat and for example, if I do something like this: new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse(text) it works.我用 SimpleDateFormat 测试了一些案例,例如,如果我这样做: new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse(text)它可以工作。

The problem is in DateTypeHandlerSupport class, the method parse validate the length:问题出在DateTypeHandlerSupport class 中,方法解析验证长度:

    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;
    }

Is there any way which I could parse the string without creating my own DateTypeHandler?有什么方法可以在不创建自己的 DateTypeHandler 的情况下解析字符串?

The trailing 00 of your string is not a valid UTC offset.字符串的尾随00不是有效的 UTC 偏移量。 I am pretty convinced that it was never meant to be one.我非常确信它从来就不是一个。 Rather your string gives us seconds with a decimal fraction of 5 digits and does not include an offset.相反,您的字符串为我们提供了 5 位小数的秒数,并且不包括偏移量。

And I am sorry, you cannot parse that.很抱歉,您无法解析。 If BeanIO internally uses SimpleDateFormat (a notorious troublemaker of a class, fortunately long outdated), then there is no way it can parse 2021-03-19T13:08:32.58600 correctly.如果 BeanIO 内部使用SimpleDateFormat (class 的臭名昭著的麻烦制造者,幸运的是早已过时),那么它就无法正确解析2021-03-19T13:08:32.58600 SimpleDateFormat supports only exactly three decimals of fraction on the seconds and will parse .58600 as 58600 milliseconds, that is, 58.6 seconds (that's correct). SimpleDateFormat仅支持秒的小数点后三位,并将.58600解析为 58600 毫秒,即 58.6 秒(这是正确的)。 See the links to related questions at the bottom.请参阅底部相关问题的链接。

Also your string does not conform to RFC-3339.此外,您的字符串不符合 RFC-3339。 According to RFC-3339 a timestamp must include a time-offset which must be either of "Z" / time-numoffset , where time-numoffset is ("+" / "-") time-hour ":" time-minute .根据 RFC-3339,时间戳必须包含一个time-offset ,该时间偏移量必须是"Z" / time-numoffset ,其中time-numoffset("+" / "-") time-hour ":" time-minute So examples of valid offsets include Z , +00:00 , +11:00 , -00:00 and -11:00 .因此,有效偏移量的示例包括Z+00:00+11:00-00:00-11:00 If you have received that string as RFC-3339 from somewhere, it seems that you need to educate the publisher about that format standard.如果您从某个地方收到了作为 RFC-3339 的字符串,那么您似乎需要对发布者进行有关该格式标准的教育。

Parsing your string in Java is easy.解析 Java 中的字符串很容易。

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

Output: Output:

2021-03-19T13:08:32.586 2021-03-19T13:08:32.586

The classes of java.time parse the most common variants of ISO 8601 format as their default, that is, without any specification of the format. java.time 类将最常见的 ISO 8601 格式变体解析为默认值,即没有任何格式规范。 RFC-3339 is based on ISO 8601 and is simplified compared to it. RFC-3339 基于 ISO 8601 并与之相比进行了简化。 Since your string did not include UTC offset, I parsed into a LocalDateTime , which the class for a date and time without time zone or UTC offset.由于您的字符串不包含 UTC 偏移量,我将其解析为LocalDateTime ,其中 class 用于没有时区或 UTC 偏移量的日期和时间。

Links链接

I know the current version (2.1) doesn't support the new java.time classes out of the box, but it will be in the new BeanIO project , which got new life.我知道当前版本 (2.1) 不支持开箱即用的新java.time类,但它将在新的 BeanIO 项目中获得新的生命。

While we wait for the new version to support java.time out of the box, you can implement it yourself relatively easy by creating your own org.beanio.types.TypeHandler implementation, most likely by implementing org.beanio.types.ConfigurableTypeHandler .当我们等待新版本支持java.time开箱即用时,您可以通过创建自己的org.beanio.types.TypeHandler实现相对容易地自己实现它,很可能通过实现org.beanio.types.ConfigurableTypeHandler You can view the new TemporalAccessorTypeHandler implementation and use it to roll your own for the time being until you can upgrade to the latest version.您可以查看新的 TemporalAccessorTypeHandler 实现,并暂时使用它来滚动您自己的实现,直到您可以升级到最新版本。 This discussion also shows how you can use this type handler and to configure it.讨论还显示了如何使用此类型处理程序并对其进行配置。

I'm not going to copy the code for the TemporalAccessorTypeHandler here but you can configure it this way:我不会在这里复制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"/>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM