如何才能最好地将java.util.Date
转换为Java 8 java.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 (future): delete when next version of JPA (i.e. Java 9?) supports YearMonth. See https://java.net/jira/browse/JPA_SPEC-63
@Converter(autoApply = true)
public class YearMonthConverter implements AttributeConverter<YearMonth, Date> {
@Override
public Date convertToDatabaseColumn(YearMonth attribute) {
// uses default zone since in the end only dates are needed
return attribute == null ? null : Date.from(attribute.atDay(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
}
@Override
public YearMonth convertToEntityAttribute(Date dbData) {
// TODO: check if Date -> YearMonth can't be done in a better way
if (dbData == null) return null;
Calendar calendar = Calendar.getInstance();
calendar.setTime(dbData);
return YearMonth.of(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1);
}
}
是否有更好(更清洁,更短)的解决方案(两个方向)?
答案 0 :(得分:18)
简答:
// 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());
<强>解释强>
YearMonth.from(TemporalAccessor) - 方法的JavaDoc说:
转换会提取YEAR和MONTH_OF_YEAR字段。仅当时态对象具有ISO年表,或者可以将其转换为LocalDate时,才允许提取。
所以,你需要能够:
YEAR
和MONTH_OF_YEAR
字段,或LocalDate
的东西。 让我们试试吧!
final Date date = new Date();
final Instant instant = date.toInstant();
instant.get(ChronoField.YEAR); // causes an error
这是不可能的,抛出异常:
java.time.temporal.UnsupportedTemporalTypeException:不支持的字段:年份 在java.time.Instant.get(Instant.java:571) ...
这意味着替代1会消失。关于how to convert Date to LocalDate的优秀答案解释了原因。
尽管有名称,
java.util.Date
代表时间线上的瞬间,而不是&#34;日期&#34;。存储在对象中的实际数据是自1970-01-01T00:00Z(GMT / UTC 1970年初午夜)以来的长时间毫秒数。JSR-310中与
java.util.Date
的等价类是Instant,因此有一个方便的方法可以让Instant()提供转换。
所以,Date
可以转换为Instant
,但这对我们没有帮助,是吗?
备选方案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月执行的;):
YearMonth:2015-01