6

Joda-Timeを使用して夏時間(DST) 時間前後の日付と時刻を解析および生成する際に、次の問題があります。以下に例を示します (2008 年 3 月 30 日はイタリアの夏時間の変更であることに注意してください)。

DateTimeFormatter dtf = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss");
DateTime x = dtf.parseDateTime("30/03/2008 03:00:00");
int h = x.getHourOfDay();
System.out.println(h);
System.out.println(x.toString("dd/MM/yyyy HH:mm:ss"));
DateTime y = x.toDateMidnight().toDateTime().plusHours(h);
System.out.println(y.getHourOfDay());
System.out.println(y.toString("dd/MM/yyyy HH:mm:ss"));

次の出力が得られます。

3
30/03/2008 03:00:00
4
30/03/2008 04:00:00

時間を解析すると、時間は 3 になります。私のデータ構造では、真夜中の時刻を格納する日を保存し、その日の各時間 (0-23) に何らかの値を持っています。次に、日付を書き出すときに、完全な日付時刻を再計算して、午前 0 時と正時を作ります。真夜中までの 3 時間を合計すると、04:00:00 になります。もう一度解析すると、4 時間になります。

私の間違いはどこですか?解析時に 2 時間を取得する方法や、印刷時に 3 時間を取得する方法はありますか?

また、手動で出力を作成しようとしました:

String.format("%s %02d:00:00", date.toString("dd/MM/yyyy"), h);

しかし、この場合、時間 2 に対して、有効な日付ではない 30/03/2008 02:00:00 を生成し (時間 2 が存在しないため)、解析できなくなります。

よろしくお願いいたします。フィリッポ

4

3 に答える 3

5

真夜中までの 3 時間を合計すると、04:00:00 になります。もう一度解析すると、4 時間になります。私の間違いはどこですか?

あなたはすでに、この日付がまさに時間が変わる時だと言いました。だから間違いはありません。2010 年 3 月 30 日 00:00 CEST (イタリアのタイムゾーン) は、正確には 2010 年 3 月 29 日 23:00 UTC です。3 時間を追加すると、2010 年 3 月 30 日 02:00 UTC になります。しかし、これは時刻を切り替える (UTC 01:00 に発生する) 瞬間であるため、時刻をローカル タイムゾーンに変換すると、3 月 30 日 04:00 になります。それは正しい振る舞いです。

解析時に 2 時間を取得する方法や、印刷時に 3 時間を取得する方法はありますか?

いいえ、2010 年 3 月 30 日 02:00 CESTは存在しないためです。正確に 2010 年 3 月 30 日 01:00 UTC で、UTC に対して +1 時間から +2 時間に時間を切り替えます。したがって、2010 年 3 月 30 日 00:59 UTC は 2010 年 3 月 30 日: 01:59 CEST ですが、2010 年 3 月 30 日 01 :00 UTC は 2010 年 3 月 30 日 03:00 CEST になります。その特定の日付に 02:xx 時間は存在しません。

ところで。1週間で、別の「楽しみ」が期待できます。これが参照する UTC の日付を教えてください:

2010 年 10 月 31 日 02:15 CEST ?

おもしろいのは、私たちにはわからないということです。2010 年 10 月 31 日 00:15 UTC (実際の時間の切り替え前) または 2010 年 10 月 31 日 01:15 UTC (切り替え後) のいずれかです。

これがまさに、UTC に関連して常に日付と時刻を保存し、表示する前にローカル タイム ゾーンに変換する必要がある理由です。そうしないと、あいまいになるリスクがあります。

HTH。

于 2010-10-23T13:14:32.913 に答える
4

データを保存しているデータ構造は、夏時間の日に最適ではありません。この特定の日のあなたの 1 日は 23 時間しかないはずです。

もしあなたがそうするなら:

    DateTimeFormatter dtf = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss").withLocale(Locale.US);
    DateTime x = dtf.parseDateTime("30/03/2008 00:00:00");

    DateTimeFormatter parser = DateTimeFormat.fullDateTime();
    System.out.println("Start:"+parser.print(x));

    DateTime y = x.plusHours(4);

    System.out.println("After add of 4:"+parser.print(y));

時刻が 05:00 であるという期待どおりの結果が得られます。

1 日の保存方法を変更して、日付を使用することをお勧めします。そうでない場合は、時刻を格納するときに夏時間を処理する必要があります。

このように時間を 1 時間進める場合、5 の時間として 5 ではなく 4 を保存する必要があります。また、時間を計算するときは、plusHours() を使用する必要があります。実際の時間を取得するメソッド。次のようなものでうまくいくと思います:

public class DateTest {
    private static final int HOUR_TO_TEST = 2;

  public static void main(String[] args) {
    DateTimeFormatter dtf = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss");
    DateTime startOfDay = dtf.parseDateTime("30/03/2008 00:00:00");

    /* Obtained from new DateTime() in code in practice */
    DateTime actualTimeWhenStoring = startOfDay.plusHours(HOUR_TO_TEST);

    int hourOfDay = actualTimeWhenStoring.getHourOfDay();
    int hourOffset = startOfDay.plusHours(hourOfDay).getHourOfDay();

    System.out.println("Hour of day:" + hourOfDay);
    System.out.println("Offset hour:" + hourOffset);

    int timeToSave = hourOfDay;
    if (hourOffset != hourOfDay) {
        timeToSave = (hourOfDay + (hourOfDay - hourOffset));
    }
    System.out.println("Time to save:" + timeToSave);

    /* When obtaining from db: */
    DateTime recalculatedTime = startOfDay.plusHours(timeToSave);

    System.out.println("Hour of time 'read' from db:" + recalculatedTime.getHourOfDay());
  }
}

...または基本的にそのようなもの。このルートを選択する場合は、テストを作成します。HOUR_TO_TEST を変更して、夏時間が経過したことを確認できます。

于 2010-10-23T10:44:19.930 に答える