Jpa 如何将java.util.Date转换为Java8 java.time.YearMonth
如何最好地将Jpa 如何将java.util.Date转换为Java8 java.time.YearMonth,jpa,java-8,java.util.date,Jpa,Java 8,Java.util.date,如何最好地将java.util.Date转换为Java8java.time.YearMonth 不幸的是,下面抛出了一个DateTimeException: YearMonth yearMonth = YearMonth.from(date.toInstant()); 结果: java.time.DateTimeException: Unable to obtain YearMonth from TemporalAccessor: 2015-01-08T14:28:39.183Z of typ
java.util.Date
转换为Java8java.time.YearMonth
不幸的是,下面抛出了一个DateTimeException
:
YearMonth yearMonth = YearMonth.from(date.toInstant());
结果:
java.time.DateTimeException: Unable to obtain YearMonth from TemporalAccessor: 2015-01-08T14:28:39.183Z of type java.time.Instant
at java.time.YearMonth.from(YearMonth.java:264)
...
我需要这个功能,因为我想使用JPA在数据库中存储YearMonth
值。目前JPA不支持YearMonth
,因此我提出了以下YearMonthConverter(导入省略):
//TODO(未来):当下一版本的JPA(即Java 9?)支持YearMonth时删除。看见https://java.net/jira/browse/JPA_SPEC-63
@转换器(自动应用=真)
公共类YearMonthConverter实现AttributeConverter{
@凌驾
public Date convertToDatabaseColumn(YearMonth属性){
//使用默认区域,因为最后只需要日期
return attribute==null?null:Date.from(attribute.atDay(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
}
@凌驾
public YearMonth convertToEntityAttribute(日期数据){
//TODO:检查Date->YearMonth是否不能以更好的方式完成
if(dbData==null)返回null;
日历=Calendar.getInstance();
calendar.setTime(dbData);
返回YearMonth.of(calendar.get(calendar.YEAR)、calendar.get(calendar.MONTH)+1);
}
}
是否有更好(更干净、更短)的解决方案(适用于两个方向)?简短回答:
// From Date to YearMonth
YearMonth yearMonth =
YearMonth.from(date.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate());
// From YearMonth to Date
// The same as the OP:s answer
final Date convertedFromYearMonth =
Date.from(yearMonth.atDay(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
说明:
// From Date to YearMonth
YearMonth yearMonth =
YearMonth.from(date.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate());
// From YearMonth to Date
// The same as the OP:s answer
final Date convertedFromYearMonth =
Date.from(yearMonth.atDay(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
方法的JavaDoc说:
转换将提取年中的年和月字段。仅当时态对象具有ISO年表或可以转换为LocalDate时,才允许提取
因此,您需要能够:
年度
和年度月份
字段,或LocalDate
的内容李>
让我们试试看
final Date date = new Date();
final Instant instant = date.toInstant();
instant.get(ChronoField.YEAR); // causes an error
这是不可能的,将引发异常:
java.time.temporal.UnsupportedTemporalTypeException:不支持的字段:年
at java.time.Instant.get(Instant.java:571)
这意味着备选方案1将被淘汰。在这个关于的极好的回答中解释了这个问题的原因
尽管名称不同,java.util.Date
表示时间线上的一个瞬间,而不是“日期”。自1970-01-01T00:00Z(1970 GMT/UTC开始时的午夜)以来,存储在对象中的实际数据是一个很长的毫秒计数
JSR-310中与java.util.Date
等价的类是Instant,因此有一个方便的方法toInstant()来提供转换
因此,日期
可以转换为即时
,但这对我们没有帮助,是吗
然而,备选方案2证明是成功的。将Instant
转换为LocalDate
,然后使用YearMonth.from(TemporalAccessor)
-方法
Date date = new Date();
LocalDate localDate = date.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
YearMonth yearMonth = YearMonth.from(localDate);
System.out.println("YearMonth: " + yearMonth);
输出为(自2015年1月执行代码以来;):
年份月份:2015-01
就个人而言,我会避免映射到
java.util.Date
,因为a)它不是java.sql.
-类型,b)包括隐式时区(性能差和系统时区使用模糊),c)sql没有为年-月定义此类类型。最好使用@MenoHochschild将YearMonth
映射为整数:这是个好主意-唯一需要注意的是,在查看数据库本身时,它是不可读的。在我的例子中没有问题…好吧,对于直接查看db内容来说,仅仅一个整数是不可读的,但是请注意,由于时区转换和db/服务器设置,映射到j.u.Date可以更改可视化的日期和月份(正如db管理员所看到的)。我选择了该解决方案-没有回答我最初的问题,但是在我的特殊情况下帮助我。。。public Integer convertToDatabaseColumn(YearMonth YearMonth){return(YearMonth==null)?null:(int)YearMonth.getLong(ChronoField.PROLEPTIC_MONTH)}public YearMonth convertToEntityAttribute(Integer dbData){return(dbData==null)?null:YearMonth.from(YearMonth.now().with(ChronoField.PROLEPTIC_MONTH,dbData))}