これは確かに、さまざまな種類のカレンダーに関係しています。java.sql.Timestamp
、 のようjava.util.Date
に、カレンダー情報はありません。1970 年からのミリ秒数としてのみ格納されているため、グレゴリオ暦が公式に制定された 1582 年 10 月 4 日から 10 月 15 日までの間にジャンプがあったという暗黙の仮定があります。古いユリウス暦に代わって採用されました。したがって、1582 年 10 月 7 日を表す Date (または Timestamp) オブジェクトを持つことはできません。そのような日付を作成しようとすると、自動的に 10 日後になります。例えば:
Calendar c = Calendar.getInstance();
c.setTimeZone(TimeZone.getTimeZone("UTC"));
c.set(1582, Calendar.OCTOBER, 7, 0, 0, 0);
c.set(Calendar.MILLISECOND, 0);
d = c.getTime();
System.out.println("Date: " + d);
// Prints:
// Date: Sun Oct 17 00:00:00 GMT 1582
言い換えれば、Date オブジェクトには暗黙のユリウス暦とグレゴリオ暦の年表があり、これら 2 つの間で自動的に切り替わります。
JodaTime は少し賢く、継続ユリウス暦、先発グレゴリオ暦、ユリウス暦とグレゴリオ暦の混合、グレゴリオ暦とほぼ同じ標準 ISO 暦など、いくつかの暦をサポートしています。methodの JavaDocLocalDate.fromCalendarFields
を読むと、次のことが言及されていることがわかります。
このファクトリ メソッドは、カレンダーのタイプを無視し、常に ISO 暦で LocalDate を作成します。
ユリウス暦とグレゴリオ暦の混合暦は、Java の暗黙的な日付のように動作し、2 つの異なる暦が自動的に切り替わります。純粋な年表は、その暦体系が永遠に使用されていることを前提としているため、たとえば、グレゴリオ暦が最初から使用されていると想定しています。
各 Chronology が 1111-11-11 の日付をどのように扱うかを見てみましょう。
Calendar c = Calendar.getInstance();
c.setTimeZone(TimeZone.getTimeZone("UTC"));
c.set(1111, Calendar.NOVEMBER, 11, 0, 0, 0);
c.set(Calendar.MILLISECOND, 0);
Date d = c.getTime();
System.out.println("Date: " + d + " (" + d.getTime() + " milliseconds)");
System.out.println("ISO: " + new DateTime(d, ISOChronology.getInstance(DateTimeZone.forID("UTC"))));
System.out.println("Julian+Gregorian: " + new DateTime(d, GJChronology.getInstance(DateTimeZone.forID("UTC"))));
System.out.println("Julian: " + new DateTime(d, JulianChronology.getInstance(DateTimeZone.forID("UTC"))));
System.out.println("Gregorian: " + new DateTime(d, GregorianChronology.getInstance(DateTimeZone.forID("UTC"))));
次のようになります。
Date: Sat Nov 11 00:00:00 GMT 1111 (-27079747200000 milliseconds)
ISO: 1111-11-18T00:00:00.000Z
Julian+Gregorian: 1111-11-11T00:00:00.000Z
Julian: 1111-11-11T00:00:00.000Z
Gregorian: 1111-11-18T00:00:00.000Z
ご覧のとおり、2 つの現代の年表 (ISO とグレゴリオ暦) は、それらが最初から使用されていた場合に正しい日付を報告しますが、ユリウス暦を使用する 2 つの暦は、当時知られていた日付を報告します。後から考えると、実際の春分の日と比較して 7 日ずれていることがわかっています。
スイッチの周りで何が起こったのか見てみましょう:
c.set(1582, Calendar.OCTOBER, 15, 0, 0, 0);
d = c.getTime();
System.out.println("Date: " + d + " (" + d.getTime() + " milliseconds)");
System.out.println("ISO: " + new DateTime(d, ISOChronology.getInstance(DateTimeZone.forID("UTC"))));
System.out.println("Julian+Gregorian: " + new DateTime(d, GJChronology.getInstance(DateTimeZone.forID("UTC"))));
System.out.println("Julian: " + new DateTime(d, JulianChronology.getInstance(DateTimeZone.forID("UTC"))));
System.out.println("Gregorian: " + new DateTime(d, GregorianChronology.getInstance(DateTimeZone.forID("UTC"))));
最終的には次のようになります。
Date: Fri Oct 15 00:00:00 GMT 1582 (-12219292800000 milliseconds)
ISO: 1582-10-15T00:00:00.000Z
Julian+Gregorian: 1582-10-15T00:00:00.000Z
Julian: 1582-10-05T00:00:00.000Z
Gregorian: 1582-10-15T00:00:00.000Z
後に残るのはユリウス暦だけです。これは、グレゴリオ暦をまだ受け入れていないすべての国で有効な日付でした。当時は多くの国でした。ギリシャは 1923 年に切り替えを行いました...
その 1 ミリ秒前の日付は次のとおりです。
c.add(Calendar.MILLISECOND, -1);
d = c.getTime();
System.out.println("Date: " + d + " (" + d.getTime() + " milliseconds)");
System.out.println("ISO: " + new DateTime(d, ISOChronology.getInstance(DateTimeZone.forID("UTC"))));
System.out.println("Julian+Gregorian: " + new DateTime(d, GJChronology.getInstance(DateTimeZone.forID("UTC"))));
System.out.println("Julian: " + new DateTime(d, JulianChronology.getInstance(DateTimeZone.forID("UTC"))));
System.out.println("Gregorian: " + new DateTime(d, GregorianChronology.getInstance(DateTimeZone.forID("UTC"))));
意味:
Date: Thu Oct 04 23:59:59 GMT 1582 (-12219292800001 milliseconds)
ISO: 1582-10-14T23:59:59.999Z
Julian+Gregorian: 1582-10-04T23:59:59.999Z
Julian: 1582-10-04T23:59:59.999Z
Gregorian: 1582-10-14T23:59:59.999Z
ISO とグレゴリオ暦は、10 月 15 日より前にグレゴリオ暦がなかったため、グレゴリオ暦には実際には存在しなかった日付を報告しますが、この日付は拡張された先発的なグレゴリオ暦で有効です。紀元前の記念碑に記された紀元前の日付を見つけるようなものです...キリストが生まれる前に、彼らがキリストの前にいたことを誰も知りませんでした。
したがって、問題の根本は、測定しているカレンダーがわからないため、日付文字列があいまいであることにあります。5772年は未来の年ですか、それとも現在のヘブライ年ですか? Java は、ユリウス暦とグレゴリオ暦が混在する暦を想定しています。JodaTime はさまざまなカレンダーを幅広くサポートしており、デフォルトでは ISO8601 暦を想定しています。日付は、1111 年に使用されていたユリウス暦から現在使用されている ISO 暦に自動的に変換されます。JodaTime で強化されたタイムスタンプでクラスと同じ年表を使用する場合は、JodaTime オブジェクトを構築java.sql.Timestamp
するときに明示的に を選択します。GJChronology