银河

SKYIV STUDIO

  博客园 :: 首页 :: 博问 :: 闪存 :: :: :: 订阅 订阅 :: 管理 ::

我们先看看以下 C# 程序:

01:  using System;
02:  using System.Globalization;
03:  
04:  class Program
05:  {
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.java
ben@ben-1520:~/work$ java GregorianTest
Thu Oct 04 00:00:00 CST 1582
Fri Oct 15 00:00:00 CST 1582
ben@ben-1520:~/work$ 

注意,java.util.GregorianCalendar 类的构造函数中月份是从 0 起始的,因此 9 表示十月。

可以看出以下两点:

  1. 一五八二年十月四日是星期四。
  2. 一五八二年十月四日的下一天是:一五八二年十月十五日,星期五。 

到底谁是正确的呢? 

 

我们来看看 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 20
16 17 18 19 20 21 22  31                    21 22 23 24 25 26 27
23 24 25 26 27 28 29                        28 29 30
30                                          
ben@ben-1520:~/work$ 

可以看到一五八二年十月四日的确是星期四,而且其下一天是一五八二年十月十五日星期五,因此一五八二年十月只有二十一天。

 

如果下载了 Visual J# Redistributable Packages,那么在 C# 语言中也可以使用 java.util.GregorianCalendar 类:

01:  using System;
02:  using java.util;
03:  
04:  class Program
05:  {
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 1582
Tue Sep 25 00:00:00 GMT+08:00 1582
Wed Sep 26 00:00:00 GMT+08:00 1582
Thu Sep 27 00:00:00 GMT+08:00 1582
Fri Sep 28 00:00:00 GMT+08:00 1582
Sat Sep 29 00:00:00 GMT+08:00 1582
Sun Sep 30 00:00:00 GMT+08:00 1582
Mon Oct 01 00:00:00 GMT+08:00 1582
Tue Oct 02 00:00:00 GMT+08:00 1582
Wed Oct 03 00:00:00 GMT+08:00 1582
Thu Oct 04 00:00:00 GMT+08:00 1582
Tue 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。

 

参考资料

  1. Gregorian calendar
  2. Julian calendar
  3. .NET Framework Class Library: Calendar Class
  4. .NET Framework Class Library: GregorianCalendar Class
  5. .NET Framework Class Library: JulianCalendar Class
  6. .NET Framework Class Library: ChineseLunisolarCalendar Class
  7. Visual J# Redistributable Packages
  8. java.util.GregorianCalendar
  9. java.util.GregorianCalendar(中文)
  10. C Library: ctime (time.h)
  11. C Library: ctime (time.h): struct tm 
  12. boost: Gregorian
  13. Ruby: date.rb - date and time library
  14. Python: datetime — Basic date and time types
  15. Perl: Date::Calc - Gregorian calendar date calculations
posted on 2010-06-14 00:25  银河  阅读(7391)  评论(13编辑  收藏  举报