问题描述
我正在尝试解析这样的字符串日期: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)
有效。
问题出在DateTypeHandlerSupport
类中,方法解析验证长度:
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
(臭名昭著的类麻烦制造者,幸运的是早已过时),那么它就无法正确解析 2021-03-19T13:08:32.58600
。 SimpleDateFormat
仅支持秒的三位小数,并将 .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 的类将 ISO 8601 格式的最常见变体解析为它们的默认值,即没有任何格式规范。 RFC-3339 基于 ISO 8601 并与之相比进行了简化。由于您的字符串不包含 UTC 偏移量,因此我将其解析为 LocalDateTime
,该类用于不带时区或 UTC 偏移量的日期和时间。
链接
- Oracle tutorial: Date Time 解释如何使用 java.time。
- 相关问题:
- Request for Comments: 3339: Date and Time on the Internet: Timestamps。
我知道当前版本 (2.1) 不支持开箱即用的新 java.time
类,但它会在获得新生命的 new BeanIO project 中提供。
虽然我们等待新版本开箱即用地支持 java.time
,但您可以通过创建自己的 org.beanio.types.TypeHandler
实现(最有可能通过实现 org.beanio.types.ConfigurableTypeHandler
)来相对轻松地实现它。您可以查看 new TemporalAccessorTypeHandler implementation 并暂时使用它来推出您自己的版本,直到您可以升级到最新版本。此 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"/>