Java 8のjava.time:インスタントとLocalDateTimeでのTemporalUnitの追加



localdatetime 比較 (1)

私はJava 8で新しいjava.timeパッケージを使いこなしています。私はjava.util.Dateを提供する従来のデータベースを持っています。これはInstantに変換します。

私がしようとしているのは、別のデータベースフラグに基づいている期間を追加することです。 私は日、週、月、年を追加することができます。 私は自分が何を追加しているか気にしたくないので、将来的にはもっと多くのオプションを追加したいと考えています。

私の最初の考えはInstant.plus()が、それは1日以上の値に対して私にUnsupportedTemporalTypeExceptionを与えます。 インスタントは、大きな時間単位の操作をサポートしていないようです。 LocalDateTimeLocalDateTimeは何でもLocalDateTime

それは私にこのコードを与えます:

private Date adjustDate(Date myDate, TemporalUnit unit){
    Instant instant = myDate.toInstant();
    LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    dateTime = dateTime.plus(1, unit);
    Instant updatedInstant = dateTime.atZone(ZoneId.systemDefault()).toInstant();
    return new Date(dueInstant.toEpochMilli());
}

さて、これは私の初めての新しい時間APIを使用しているので、私はここで何かを見逃しているかもしれません。 しかし、私は行く必要があります私にはclunkyと思われる:

Date --> Instant --> LocalDateTime --> do stuff--> Instant --> Date.

私が日付部分を使用する必要がなくても、私はまだそれは少し厄介だと思うでしょう。 だから私の質問はこれです、私はこれを完全に間違っていると、これを行うための最善の方法は何ですか?

編集 :コメントの議論を拡大する。

私は、LocalDateTimeとInstantがjava.util.Dateとjava.sql.Timestampでどのように遊んでいるかについて、より良い考えがあると思います。 みんな、ありがとう。

さて、実際的な考慮事項。 ユーザーが世界の任意の時間帯にどこからでも日付を送信したとします。 彼らは2014-04-16T13:00:00を送って、LocalDateTimeに解析することができます。 次に、これを直接java.sql.Timestampに変換し、データベースに保存します。

さて、何もせずに、自分のjava.sql.timestampをデータベースからLocalDateTimetimestamp.toLocalDateTime()を使ってLocalDateTimeに変換します。 すべての良い。 次に、ISO_DATE_TIMEの書式設定を使用してこの値をユーザーに返します。 結果は2014-04-16T09:00:00です。

この違いは、UTCへの/からの暗黙的な変換のためです。 私のデフォルトタイムゾーンは、なぜその数が4時間遅れているのかを説明する値(EDT、UTC-4)に適用されていると思います。

新しい質問。 現地時間からUTCへの暗黙の変換はどこで行われていますか? タイムゾーンを維持するためのよりよい方法は何ですか。 ローカル時間から文字列(2014-04-16T13:00:00)をLocalDateTimeないでLocalDateTime 。 ユーザー入力からタイムゾーンが必要ですか?


私は先に進み、私の最終的な解決策と非常に長いコメントチェーンの一種の要約に基づいて回答を投稿します。

開始するには、以下の全体の変換チェーンを使用します。

Date --> Instant --> LocalDateTime --> Do stuff --> Instant --> Date

タイムゾーン情報を保持し、カレンダーとその中のすべてのコンテキストを認識しているオブジェクトのようなDateの操作を行う必要があります。 それ以外の場合は、暗黙的にローカルタイムゾーンに変換されるリスクがあります。人間が読める形式に変換しようとすると、時間が変わる可能性があります。

たとえば、 java.sql.TimestampクラスのtoLocalDateTime()メソッドは、暗黙的にデフォルトのタイムゾーンに変換されます。 これは私の目的には望ましくありませんでしたが、必ずしも悪い行為ではありません。 しかし、それを知ることは重要です。 これは、レガシJavaの日付オブジェクトからLocalDateTimeオブジェクトに直接変換する際の問題です。 レガシーオブジェクトは一般的にUTCと見なされるため、変換ではローカルタイムゾーンオフセットが使用されます。

さて、私たちのプログラムが2014-04-16T13:00:00入力を受け取り、 java.sql.Timestampとしてデータベースに保存するとしjava.sql.Timestamp

//Parse string into local date. LocalDateTime has no timezone component
LocalDateTime time = LocalDateTime.parse("2014-04-16T13:00:00");

//Convert to Instant with no time zone offset
Instant instant = time.atZone(ZoneOffset.ofHours(0)).toInstant();

//Easy conversion from Instant to the java.sql.Timestamp object
Timestamp timestamp = Timestamp.from(instant);

今度はタイムスタンプを取り、それに数日を追加します:

Timestamp timestamp = ...

//Convert to LocalDateTime. Use no offset for timezone
LocalDateTime time = LocalDateTime.ofInstant(timestamp.toInstant(), ZoneOffset.ofHours(0));

//Add time. In this case, add one day.
time = time.plus(1, ChronoUnit.DAYS);

//Convert back to instant, again, no time zone offset.
Instant output = time.atZone(ZoneOffset.ofHours(0)).toInstant();

Timestamp savedTimestamp = Timestamp.from(output);

ISO_LOCAL_DATE_TIMEの形式で人間が読める文字列として出力するだけでISO_LOCAL_DATE_TIMEます。

Timestamp timestamp = ....
LocalDateTime time = LocalDateTime.ofInstant(timestamp.toInstant(), ZoneOffset.ofHours(0));
String formatted = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(time);




java-time