我正试图通过以下方式使用OpenCsv从CSV解析Instant:
@CsvDate("yyyy-MM-dd hh:mm:ss")
@CsvBindByName(column = "date")
private Instant date;
我知道OpenCsv应该支持java.time
。
但当尝试使用它时,我会遇到以下异常:
分析CSV行时出错:8。
。。。
由以下原因引起:java.time.format.DateTimeParseException:无法解析文本"2022-04-21 00:00:00":无法从TemporalAccessor:{HourOfAmPm=0,MicroOfSecond=0,NanoOfSecond=0、MilliOfSecond=0,MinuteOfHour=0,SecondOfMinute=0},ISO解析为java.time.fformat.parsed 类型的2022-04-21
。。。
由以下原因引起:java.time.DateTimeException:无法从TemporalAccessor:{HourOfAmPm=0,MicroOfSecond=0,NanoOfSecond=0、MilliOfSecond=0,MinuteOfHour=0,SecondOfMinute=0},ISO解析为java.time.format.Parsed 类型的2022-04-21
。。。
由java.time.temporal.UnsupportedTemporalTypeException引起:不支持的字段:InstantSeconds
我的调查表明,根本原因是缺少时区,但我的问题是如何仅使用注释指定时区?
请参阅DateTimeFormatter。应为HH
,持续24小时(0-23(,或hh
,持续12小时(1-12(。该错误是由小时"引起的;00";。幸运的是,否则你将只有前半天的时间。
参见h、k、h和k。
类Instant
不使用秒之类的单位,在内部更为长。使用LocalDateTime
作为您的格式。
我的调查得出的结论是,根本原因是缺少时区,但我的问题是如何仅使用注释指定时区?
我还没有找到更改OpenCSV使用的DateTimeFormatter
时区的方法。理论上,您可以使用@CsvCustomBindByName
,并提供一个自定义转换器,在该转换器中,您可以将自己的DateTimeFormatter
与所需时区一起使用。
但是,如果您还控制CSV的生成方式,您可以简单地使用以下日期时间模式使其与Instant
:一起工作
@CsvBindByName(column = "date")
@CsvDate(
value = "yyyy-MM-dd'T'HH:mm:ssX",
writeFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'",
writeFormatEqualsReadFormat = false)
private Instant date;
value
是从CSV文件中读取bean时使用的模式。X
是一个模式字母,它将对应于区域偏移,即当读取"Z"字符时,它将假定时间为UTC+00:00。参见文档。
当将bean写入CSV文件时,将使用writeFormat
模式,并且需要有所不同,您需要在末尾手动打印"Z"字符,从而获得转义的'Z'
。原因是内部OpenCSV在编写Instant
:时会执行以下操作
LocalDateTime ldt = LocalDateTime.ofInstant((Instant) value, ZoneId.of("UTC"));
return writeDtf.format(ldt);
LocalDateTime
没有时区,因此不能使用X
。可以说,他们可以做以下事情:
return writeDtf.withZone(ZoneOffset.UTC).format(value);
这将允许我们使用X
。为了保持一致,他们也可以在将日期解析为Instant
时执行同样的操作。