2015-01-08 6 views
9

java.util.DateをJava 8 java.time.YearMonthに変換するにはどうすればよいですか?java.util.DateをJava8に変換する方法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); 
    } 
} 

は(両方向のための)より良い(クリーナー、短い)解決策はありませんか?

+1

私はjava.util.Date 'へのマッピングを避けるだろうa)それは 'java.sql。*' -typeではないので、b)暗黙的なタイムゾーン(パフォーマンスが悪く、システムタイムゾーンがあいまいになります)を含んでいるため、c)SQLはそのような型を年月に定義しません。 [PROLEPTIC_MONTH](http://docs.oracle.com/javase/8/docs/api/java/time/temporal/ChronoField.html#PROLEPTIC_MONTH)を使用して、「YearMonth」を整数にマップすることをお勧めします。 –

+0

@MenoHochschild:良いアイデアです - 注意しなければならないのは、データベース自体を見るときに読み込みができないということです。私の場合は問題ありません... – Sebastian

+0

DBコンテンツの直接ビューでは整数だけが読み込めませんが、juDateへのマッピングはタイムゾーンのために視覚化された日付と月を(db管理者が見るように)変更することができます。コンバージョンとdb/server-settingsが含まれます。 –

答えて

13

短い答え:

// 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()); 

説明:

言う-method YearMonth.from(TemporalAccessor)のJavaDocを:

変換はYEARとMONTH_OF_YEARフィールドを抽出します。抽出は、一時オブジェクトがISOの年表を持つ場合、またはLocalDateに変換できる場合にのみ許可されます。

だから、あなたのことができるようにするか必要があります。

  1. あなたはLocalDateに変換することができるものを使用する必要がありますYEARMONTH_OF_YEARフィールドを抽出、または

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は、その名前にかかわらず、「日付」ではなく、タイムライン上の瞬間を表します。オブジェクト内に格納される実際のデータは、1970-01-01T00:00Z(1970 GMT/UTCの開始時の深夜)から長いミリ秒数です。

JSR-310のjava.util.Dateと同等のクラスはインスタントですので、変換を提供する便利なメソッドtoInstant()があります。

ので、DateInstantに変換することができますが、それはそれをやった、私たちを助けにはなりませんでしたか?

しかし、代替2が成功することがわかります。 InstantLocalDateに変換してから、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

関連する問題