20

GregorianCalendar を使用しようとして、特定の日付からの日数を計算しているときに特異点に行き詰まりました。scala インタープリターで、次のように入力しました。

scala>import java.util.GregorianCalendar
scala>import java.util.Calendar
scala>val dateToday = new GregorianCalendar(2012,Calendar.MAY,22).getTimeInMillis()
dateToday: Long = 1337637600000
scala>val days1 = (dateToday - (new GregorianCalendar(1976,Calendar.MARCH,28).getTimeInMillis())) / (1000*3600*24)
days1: Long = 13203
scala>val days2 = (dateToday - (new GregorianCalendar(1976,Calendar.MARCH,29).getTimeInMillis())) / (1000*3600*24)
days2: Long = 13203

1976 年が閏年であるという事実が重要かどうかはわかりませんが、days1 と days2 は 1 で区切られているはずです。これは、1970 年以来、この特異点が発生した唯一の瞬間です。

何が起こっているのか知りたくて、前述の 2 つの日付の差を計算すると、正確に 23 時間の差しかありません。その日に何が起こったのですか?ウィキペディアは明らかにそれについて何も述べていません。

さらに重要なのは、特定の日付からの実際の日数を計算する方法です。

4

3 に答える 3

46

問題

サマータイムは 23 時間しかありません。

そして、この3 月 28 日によると、1976 年は少なくともパリでは夏時間でした。その日の午前 1 時から午前 2 時までの時間は存在しませんでした。

私のコンピューターでは正しいので、ロケールの問題である必要があります。

scala> val days1 = (dateToday - (new GregorianCalendar(1976, Calendar.MARCH, 28).getTimeInMillis())) / (1000 * 3600 * 24)
days1: Long = 13203

scala> val days2 = (dateToday - (new GregorianCalendar(1976, Calendar.MARCH, 29).getTimeInMillis())) / (1000 * 3600 * 24)
days2: Long = 13202

私はパリにも、その日に時間が変更された他の場所にもいません。私がいる 1976 年 4 月 25 日に時間が変わりました。そのため、その日に「スキップされた日」の動作が発生します。

scala> val days3 = (dateToday - (new GregorianCalendar(1976, Calendar.APRIL, 25).getTimeInMillis())) / (1000 * 3600 * 24)
days3: Long = 13175

scala> val days4 = (dateToday - (new GregorianCalendar(1976, Calendar.APRIL, 26).getTimeInMillis())) / (1000 * 3600 * 24)
days4: Long = 13175

Erwin はコメントの中で、ここで誤った日付の違いに気付いた唯一の理由は、夏時間が修正されたときに、他のすべての夏時間がそれらの年に発生する 25 時間制の日によって相殺されていることだと指摘しています。

ソリューション

日付処理には、より優れたライブラリを使用してください。joda -timeライブラリはそれを正しく行います (全体的に優れた日付/時刻フレームワークであるだけでなく):

import org.joda.time.Days
import org.joda.time.DateTimeConstants
import org.joda.time.DateMidnight

val d1 = new DateMidnight(1976, DateTimeConstants.APRIL, 25)
val d2 = new DateMidnight(1976, DateTimeConstants.APRIL, 26)
val x = Days.daysBetween(d1, d2).getDays()
println(x) // 1
于 2012-05-22T08:38:33.600 に答える
4

浮動小数点除算のオプションが利用できない場合、私が考えることができる最良の答えは、2 日間の差を計算する際に 1 時間 (1000*3600) を追加することです。

scala> (dateToday - (new GregorianCalendar(1976, Calendar.MARCH, 28).getTimeInMillis()) + 1000*3600) / (1000 * 3600 * 24)
days1: Long = 13204
scala> (dateToday - (new GregorianCalendar(1976, Calendar.MARCH, 29).getTimeInMillis()) + 1000*3600) / (1000 * 3600 * 24)
days1: Long = 13203

うるう時間に苦しむことはもうないので、すべての日付で機能するはずです。

于 2012-05-22T09:18:37.903 に答える
3

dhg は私の考えを指摘しました: この日は「サマータイム」の日です。この日は 23 時間しかないため、ユークリッドを 1 日で割ると 0 になります。

実際、GregorianCalendar オブジェクトを使用すると、日付がミリ秒単位でしか使用されないため、整数として 1 日で除算しても、結果が切り捨てられるだけです。

ユークリッド (整数) 除算の代わりに、浮動小数点除算を実行してから、結果を丸めます。

于 2012-05-22T08:54:10.153 に答える