2017-02-22 14 views
1

私は"2016-03-28T02:00:00+0200"でテストしていを使用した日からその日を減算した後、間違った結果を取得のLocalDateTimeとZonedDateTime

1日を引いた後、DSTが適用され、出力は次のようになります。

"2016-03-27T03:00:00 + 0200"

しかし、私はこの取得しています:

2016-03-26T01:00 + 01:00 [ヨーロッパ/ストックホルム]

CODE:

public class DateFormatSampleCode { 
    public static void main(String[] args) 
    { 
     LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(1459123200, 0, ZoneOffset.UTC); 

     System.out.println(localDateTime); 
     localDateTime = localDateTime.minusDays(1); 
     System.out.println(localDateTime); 

     ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("Europe/Stockholm")); 

     System.out.println(zonedDateTime); 
    } 
} 

チェックして、私が間違っているつもりどこ指摘してください。

+1

夏時間の概念を持たない*ローカル*の日付/時刻から日を差し引くことはできません。夏時間規則を適用することを期待しています。 – RealSkeptic

+0

@RealSkepticこれを行う方法を提案できますか? –

+0

ゾーン化された日付/時刻を使用する場合は、ZonedDateTimeを使用します。 'LocalDateTime'は使わないでください。 – RealSkeptic

答えて

1

私は上記の質問に答えることができると思います。

ここにコードがあります。

public ZonedDateTime addDays(long myUTCTimeInSeconds, int days) { 
    Instant instant = Instant.ofEpochSecond(myUTCTimeInSeconds); 
    ZonedDateTime dateTimeWithOffSet = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault()); 
    if (localDays >= 0) { 
     dateTimeWithOffSet = dateTimeWithOffSet.plusDays(localDays); 
    } else { 
     dateTimeWithOffSet = dateTimeWithOffSet.minusDays(abs(localDays)); 
    } 
    return dateTimeWithOffSet; 
} 

タイムゾーンはシステムのものと異なる場合は、我々はデフォルトタイムゾーンを設定し、などの方法上記の呼び出し後にタイムゾーンをリセットすることができます:あなたは解決策を見つけた

TimeZone systemDefaultTimeZone = TimeZone.getDefault(); 
TimeZone.setDefault(TimeZone.getTimeZone(timezone)); 

addDays(1459123200, 1); 
TimeZone.setDefault(systemDefaultTimeZone); 
0

良い、私は思いますいくつかの洞察を加えて、少し改良してyour answerに提案したいと思います。

TimeZone.setDefaultを使用してJVMのデフォルトタイムゾーンを設定することは、これを実行する最善の方法ではありません。たいていの場合はうまくいくかもしれませんが、より複雑な環境でこのコードを実行すると、少し危険でエラーが発生しやすくなります。

TimeZone.setDefaultは、のデフォルトのタイムゾーンを JVMに変更したためです。同じJVMで実行されている他のアプリケーションは、その影響を受けます。同じアプリケーションの他の部分も影響を受けます。同じコードであっても、複数のスレッドで実行すると、結果が間違ってしまうことがあります(race conditions are hard to debug)。

あなたはTimeZone.setDefault(TimeZone.getTimeZone(timezone));を使用していることに気付きました。つまり、特定のタイムゾーンで作業しているため、JVMのデフォルトに依存する必要はありません。特定のタイムゾーン名を使用している場合は、デフォルトのタイムゾーン名の代わりに使用してください。作っ

public ZonedDateTime addDays(long myUTCTimeInSeconds, int days, String timezone) { 
    // get the instant from the UTC seconds 
    Instant instant = Instant.ofEpochSecond(myUTCTimeInSeconds); 
    // get the instant at the specified timezone 
    ZonedDateTime z = instant.atZone(ZoneId.of(timezone)); 

    // add days 
    return z.plusDays(days); 
} 

改善:だから私はaddDays方法は次のようにあるべきことをお勧めしますが、それに-1を渡すと

  • plusDaysはすでに1日減算します。値を確認してabsメソッドを使用する必要はありません。
  • はJVMのデフォルトのタイムゾーンを使用しないでください。代わりにZoneId.systemDefault()、あなたが既に持っているtimezone
  • instant.atZoneZonedDateTime.ofInstantと等価である(あなたがsetDefault方法で使用していたもの)を使用します。IMO、atZoneは「読みやすく」なりますが、この場合は選択とコードスタイルの問題です。最終的な結果に違いはありません。
  • これにより

、あなたができる:

// call directly, no need to change the default timezone 
System.out.println(addDays(1459123200, -1, "Europe/Stockholm")); 

これを印刷します:

2016-03-27T03:00 + 02:00 [ヨーロッパ/ストックホルム]