我們先看看以下 C# 程式:
01: using System;02: using System.Globalization;03: 04: class Program05: {06: static void Main()07: {08: Console.WriteLine(CultureInfo.CurrentCulture.Calendar);09: for (var dt = new DateTime(1582, 10, 4); dt <= new DateTime(1582, 10, 15); dt = dt.AddDays(1))10: Console.WriteLine(dt.ToString("dddd yyyy-MM-dd"));11: }12: }
其運行結果如下:
System.Globalization.GregorianCalendar星期一 1582-10-04星期二 1582-10-05星期三 1582-10-06星期四 1582-10-07星期五 1582-10-08星期六 1582-10-09星期日 1582-10-10星期一 1582-10-11星期二 1582-10-12星期三 1582-10-13星期四 1582-10-14星期五 1582-10-15
這麼看來,一五八二年十月四日是星期一。
真的如此嗎?我們來看看以下 Java 程式:
import java.util.*;public class GregorianTest{ public static void main(String[] args) { for ( GregorianCalendar dt = new GregorianCalendar(1582, 9, 4); dt.compareTo(new GregorianCalendar(1582, 9, 15)) <= 0; dt.add(Calendar.DAY_OF_MONTH, 1) ) System.out.println(dt.getTime()); }}
在 Ubuntu 10.04 作業系統下進行編譯和運行:
ben@ben-1520:~/work$ javac GregorianTest.javaben@ben-1520:~/work$ java GregorianTestThu Oct 04 00:00:00 CST 1582Fri Oct 15 00:00:00 CST 1582ben@ben-1520:~/work$
注意,java.util.GregorianCalendar 類的建構函式中月份是從 0 起始的,因此 9 表示十月。
可以看出以下兩點:
- 一五八二年十月四日是星期四。
- 一五八二年十月四日的下一天是:一五八二年十月十五日,星期五。
到底誰是正確的呢?
我們來看看 java.util.GregorianCalendar 類的說明吧:
GregorianCalendar 是 Calendar 的一個具體子類,提供了世界上大多數省/地區使用的標準日曆系統。
GregorianCalendar 是一種混合日曆,在單一間斷性的支援下同時支援儒略曆和格里高利曆系統,在預設情況下,它對應格裡高利日曆創立時的格里高利曆日期(某些省/地區是在 1582 年 10 月 15 日創立,在其他省/地區要晚一些)。可由調用方通過調用 setGregorianChange() 來更改起始日期。
曆史上,在那些首先採用格里高利曆的省/地區中,1582 年 10 月 4 日(儒略曆)之後就是 1582 年 10 月 15 日(格里高利曆)。此日曆正確地類比了這些變化。在開始格里高利曆之前,GregorianCalendar 實現的是儒略曆。格里高利曆和儒略曆之間的惟一區別就是閏年規則。儒略曆指定每 4 年就為閏年,而格里高利曆則忽略不能被 400 整除的世紀年。
GregorianCalendar 可實現預期的 格里高利曆和儒略曆。也就是說,可以通過在時間上無限地向後或向前外推當前規則來計算日期。因此,對於所有的年份,都可以使用 GregorianCalendar 來產生有意義並且一致的結果。但是,採用現代儒略曆規則時,使用 GregorianCalendar 得到的日期只在曆史上從公元 4 年 3 月 1 日之後是準確的。在此日期之前,閏年規則的應用沒有規則性,在 45 BC 之前,甚至不存在儒略曆。
這樣就清楚了,Java 平台是正確的,而 .NET Framework Base Class Library 中的 DateTime 是有問題的。
Gregorian calendar 也就是我國現行的西曆。
在 Ubuntu 10.04 作業系統下運行以下命令:
ben@ben-1520:~/work$ ncal -3 -s IT 10 1582 九月 1582 十月 1582 十一月 1582 日 一 二 三 四 五 六 日 一 二 三 四 五 六 日 一 二 三 四 五 六 1 1 2 3 4 15 16 1 2 3 4 5 6 2 3 4 5 6 7 8 17 18 19 20 21 22 23 7 8 9 10 11 12 13 9 10 11 12 13 14 15 24 25 26 27 28 29 30 14 15 16 17 18 19 2016 17 18 19 20 21 22 31 21 22 23 24 25 26 2723 24 25 26 27 28 29 28 29 3030 ben@ben-1520:~/work$
可以看到一五八二年十月四日的確是星期四,而且其下一天是一五八二年十月十五日星期五,因此一五八二年十月只有二十一天。
如果下載了 Visual J# Redistributable Packages,那麼在 C# 語言中也可以使用 java.util.GregorianCalendar 類:
01: using System;02: using java.util;03: 04: class Program05: {06: static void Main()07: {08: var dt = new GregorianCalendar(1582, 9, 4);09: for (var i = 0; i < 12; i++)10: {11: Console.WriteLine(dt.getTime());12: dt.add(Calendar.DAY_OF_MONTH, 1);13: }14: }15: }
注意,該程式需要引用 vjslib.dll 。這個程式的運行結果如下:
Thu Oct 04 00:00:00 GMT+08:00 1582Tue Sep 25 00:00:00 GMT+08:00 1582Wed Sep 26 00:00:00 GMT+08:00 1582Thu Sep 27 00:00:00 GMT+08:00 1582Fri Sep 28 00:00:00 GMT+08:00 1582Sat Sep 29 00:00:00 GMT+08:00 1582Sun Sep 30 00:00:00 GMT+08:00 1582Mon Oct 01 00:00:00 GMT+08:00 1582Tue Oct 02 00:00:00 GMT+08:00 1582Wed Oct 03 00:00:00 GMT+08:00 1582Thu Oct 04 00:00:00 GMT+08:00 1582Tue Sep 25 00:00:00 GMT+08:00 1582
可以看出,一五八二年十月四日的確是星期四。但是,其下一天怎麼變成了一五八二年九月二十五日星期二了?看來微軟的 vjslib.dll 有問題。
.NET Framework Base Class Library 中有 System.Globalization.GregorianCalendar 類,但是該類不能正確處理一五八二年十月四日。
(如果由使用者自己指定使用儒略曆還是格里曆,.NET 平台的 System.Globalization.GregorianCalendar 相關的類還是能夠正常工作的。請參閱“Ubuntu 中的程式設計語言(上)”的有關論述。 ---- 引用自13樓的評論)
在 C 語言中,日期時間相關的資料結構和函數位於 time.h 中, 是從 1900 年起始的,因此就無法表達 1582 年的日期了。
在 C++ 語言及其標準庫中,我沒有發現有關 Gregorian calendar 相關的內容。但是著名的 C++ boost 庫中包含了 Gregorian Date System。
在 Ruby 語言中,date.rb - date and time library 可以正確處理 Gregorian calendar。
在 Python 語言中,datetime — Basic date and time types 可以正確處理 Gregorian calendar。
在 Perl 語言中,Date::Calc - Gregorian calendar date calculations 可以正確處理 Gregorian calendar。
參考資料
- Gregorian calendar
- Julian calendar
- .NET Framework Class Library: Calendar Class
- .NET Framework Class Library: GregorianCalendar Class
- .NET Framework Class Library: JulianCalendar Class
- .NET Framework Class Library: ChineseLunisolarCalendar Class
- Visual J# Redistributable Packages
- java.util.GregorianCalendar
- java.util.GregorianCalendar(中文)
- C Library: ctime (time.h)
- C Library: ctime (time.h): struct tm
- boost: Gregorian
- Ruby: date.rb - date and time library
- Python: datetime — Basic date and time types
- Perl: Date::Calc - Gregorian calendar date calculations