這確實必須處理不同類型的日曆。 java.sql.Timestamp
與java.util.Date
一樣,沒有任何日曆信息,因爲它們僅存儲爲一個數字,即自1970年以來的毫秒數,暗示假設在1582年10月4日到10月15日之間存在跳躍,當公曆正式通過,取代舊的儒略曆。所以,你不可能有一個Date(或Timestamp)對象代表1582年10月7日。如果你試圖創建這樣一個日期,你會在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
換句話說,日期對象具有一個隱含的儒略+公曆年表,這兩個之間自動切換。
JodaTime有點智能,它支持幾種年代學,包括Julian繼承,Gregorian的proleptic,混合的Julian + Gregorian,以及與Gregorian幾乎相同的標準ISO年表。如果你讀the JavaDoc of the LocalDate.fromCalendarFields
method,你會看到,它提到:
此工廠方法忽略了日曆的類型,並始終將創建ISO年表LOCALDATE的。
Julian + Gregorian混合年表的行爲就像隱含的Java日期,在兩個不同的日曆之間自動切換。純粹的時間表假設他們的日曆系統是永久使用的,所以例如它假定公曆從一開始就被使用。
讓我們看看各年表如何對待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
正如你可以看到,這兩個現代年表(ISO和陽曆)報告正確的日期,如果他們從一開始就使用,而使用Julian日曆的兩個報告的日期爲,因爲它是當時已知的,儘管在事後看來我們與真正的春分日期相比,我們知道它要晚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年做了開關......
一毫秒,日期是:
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日之前沒有公曆日曆,但這個日期在擴展的,盛大的公曆中有效。就像找到一個刻在BCE紀念碑上的BCE日期一樣......在基督誕生之前,沒有人知道他們在基督之前是。
因此,問題的根源在於日期字符串不明確,因爲您不知道要測量哪個日曆。今年是5772年,還是現在的希伯來語年? Java假定混合的Julian + Gregorian日曆。 JodaTime爲不同的日曆提供了廣泛的支持,默認情況下它採用ISO8601年表。您的日期會自動從1111年的Julian日曆轉換爲我們目前使用的ISO年表。如果您希望JodaTime增強的時間戳使用與java.sql.Timestamp
類相同的年表,請在構建JodaTime對象時明確選擇GJChronology
。
難道這可能與陽曆和朱利安日曆的區別?你有與1999-11-11 00:00:00相同的問題嗎? –
@RoddyoftheFrozenPeas不,我不知道。 'System.out.println(new LocalDate(Timestamp.valueOf(「1999-11-11 00:00:00」)))'打印'1999-11-11'。那是什麼意思? –
我敢打賭,因爲你使用的是本地日期,所以你會遇到從Julian日曆到Gregorian日曆(我們現在使用的)的切換。 [Wikipedia](http://en.wikipedia.org/wiki/Gregorian_calendar#Adoption)對該主題進行了體面的討論。基本上,一些國家在切換時「失去」了 - 例如。 1582年12月9日之後的那天是1582年12月20日。我敢打賭,你的差異與此有關。 –