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);
}
}
より良い(よりクリーンでより短い)解決策(両方向)はありませんか?
短い答え:
_// 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がウィンドウの外に出ることを意味します。その理由は、 DateをLocalDateに変換する方法 に関するこの優れた回答で説明されています。
その名前にもかかわらず、_
Java.util.Date
_は「日付」ではなく、タイムライン上の瞬間を表します。オブジェクト内に保存される実際のデータは、1970-01-01T00:00Z(1970 GMT/UTCの開始時の真夜中)からの長いミリ秒数です。JSR-310の_
Java.util.Date
_と同等のクラスはInstantであるため、変換を提供するための便利なメソッドtoInstant()があります。
したがって、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月に実行されたため;):
年月:2015-01