2016-11-20 14 views
0

私は本当に奇妙な動作をしています。私は、LocalDateフィールドを持ち、データベースに挿入するエンティティを作成していますが、データベースの値はいくつかの状況で変更されます。JPA EclipseLink PostgreSQL java.time.LocalDateをjava.sql.Dateとして挿入すると、間違った日付が挿入されます

[EL Fine]: sql: 2016-11-19 21:31:57.979 
--ClientSession(1809129176)--Connection(1261635736) 
--Thread(Thread[main,5,main]) 
--INSERT INTO vcc_task (creator_user, execution_end_time, execution_start_time, last_edit_time, last_edit_user, server_name, state, thread_name, version, task_type, cc_service_id, vcc, start_time, end_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
bind => [[email protected], null, null, 2016-11-20 00:31:46.016, [email protected], , 0, , 1, 0, c1, vccModel1, 2017-05-06, 2017-05-07] 

注意「2017年5月6日、2017年5月7日」:これは、デバッガを使用してログインしますSQLです。 しかし、私は、PostgreSQLを照会場合:私が書いた

SELECT * FROM vcc_task 

enter image description here

他のテストは間違って動作しません。彼らはデータベースに正しい日付を保存します。だから、私はかなり混乱しています。

私がtaskEntityを格納するために使用したのと同じEntityManagerを使用してデータベースにクエリを実行すると、正しい日付のエンティティが取得されます。しかし、別のEntityManagerを使用してクエリを実行すると、データベースから日付が取得されます。つまり、正しい日付の1日前です。それは、EMがそのキャッシュから戻ってくるので理にかなっています。しかし、私はまだ誰が日付を変えているのか、時にはそれがなぜ起こるのかを理解していない。例えば

、両方LOCALDATEコンストラクタを使用して、次のテストパス:

// private final LocalDate startTime = LocalDate.parse("2017-05-06"); 
    // private final LocalDate endTime = LocalDate.parse("2017-06-06"); 
    private final LocalDate startTime = Instant.parse("2017-05-06T00:00:00Z").atZone(ZoneOffset.UTC).toLocalDate(); 
    private final LocalDate endTime = Instant.parse("2017-06-06T00:00:00Z").atZone(ZoneOffset.UTC).toLocalDate(); 

    em = MyEntityManager.getEntityManager(); 
    final TaskDT tdt = new TaskDT(taskType, ccService, startTime, endTime, userName); 
    t1 = new TaskEntity(userName, vcc, tdt); 
    PersistLogic.persist(em, t1); 
    em.close(); 

    em = MyEntityManager.getEntityManager(); 
    final TaskEntity t2 = em.find(TaskEntity.class, tid); 
    em.close(); 

    Assert.assertNotNull(t2, "Task does exist");  
    Assert.assertEquals(t2.getVersion(), 1, "Resource Version"); 
    Assert.assertEquals(t2.getLastEditUser(), userName, "Resource Version"); 

    Assert.assertEquals(t2.getId().getVcc(), vcc, "getVcc"); 
    Assert.assertEquals(t2.getId().getTaskType(), taskType, "getTaskType"); 
    Assert.assertEquals(t2.getId().getCcService(), ccService, "getCcService"); 
    Assert.assertEquals(t2.getId().getStartTime(), startTime, "getStartTime"); 
    Assert.assertEquals(t2.getId().getEndTime(), endTime, "getEndTime"); 
    ... 

enter image description here

私はコード内のエンティティを作成するときに問題が起こっている:

// create the task 
final LocalDate taskFromD = toLocalDate(tmpFrom); 
final LocalDate taskToD = toLocalDate(tmpTo); 
final TaskDT taskDT = new TaskDT(taskType, ccServiceName, taskFromD, taskToD, userName); 
final TaskEntity newTask = new TaskEntity(userName, vccName, taskDT); 

PersistLogic.persist(em, newTask); 

に見えます同じですが、異なる動作をします。

UPDATE

これは、私はエンティティに渡すLOCALDATEにインスタントを変換する方法である:

private static LocalDate toLocalDate(Instant i) { 
    return i.atZone(ZoneOffset.UTC).toLocalDate(); 
} 

これは私が日付と背中にLOCALDATEを変換する方法です:

import java.sql.Date; 
import java.time.LocalDate; 

import javax.persistence.AttributeConverter; 
import javax.persistence.Converter; 

@Converter(autoApply = true) 
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> { 

    @Override 
    public Date convertToDatabaseColumn(LocalDate locDate) { 
     return (locDate == null ? null : Date.valueOf(locDate)); 
    } 

    @Override 
    public LocalDate convertToEntityAttribute(Date sqlDate) { 
     return (sqlDate == null ? null : sqlDate.toLocalDate()); 
    } 
} 

ご協力いただければ幸いです。私は問題は方法convertToDatabaseColumn()のコールDate.valueOf(locDate)だと思い おかげ

+0

'LocalDate'はローカルタイムゾーンに関して暗黙のうちに起こります。 'Date'は、内部的にUTCで書かれた新しいJavaの' Instant'の古いJava APIのアナログです。 'LocalDate'インスタンスを' Instant'sに変換できますか?そしてもしそうなら、彼らはあなたが見ているふるまいを発揮していますか? – scottb

+0

私は、LocalDateをDateに変換して戻すコードで更新しました。合格したテストケースは、文字列を解析して構築されたLocalDateを使用します。しかし、コードでは、それは失敗し、私はインスタントからLocalDateを作成します。違いがありますか? –

+0

この設定があるので、問題が発生します。 TimeZone.setDefault(TimeZone.getTimeZone( "UTC")); –

答えて

0

は、ここで生成された瞬間には、お使いのシステムのデフォルトのタイムゾーンでこの日付の真夜中です。

+0

いいえ、それは問題ではありません。 convertToDatabaseColumnメソッドでは、java.time.LocalDateからjava.sql.Dateに直接変換しています。私はインスタントクラスを使用していません。また、デバッグ時に、java.time.LocalDateが正しくsql.Dateに変換されます。それはフレームワークの問題のようなものです。 LocalDateの代わりにInstantを使用することに決めました。インスタントクラスでは変換の問題はありません。 –

+0

LocalDateにはタイムゾーンとの関連性がなく、java.sql.Dateとは関係ありません。 UTC + 4に設定されたタイムゾーンでシステムでこの変換を実行すると、結果はUTC + 4でこの日の0:00になり、UTC + 0で前日の20:00に相当しますタイムゾーンの性質のために。 – mspiro

関連する問題