儒略历日算法

儒略日数(简称儒略日)
儒略日数是指从公元 -4712 年开始连续计算日数得出的天数及不满一日的小数,通常记为 JD (**)。传统上儒略日的计数是从格林尼治平午,即世界时12点开始的。若以力学时(或历书时)为标尺,这种计数通常表达为“儒略历书日”,即JDE (**),其中E只是一种表征,即按每天86400个标准秒长严格地计日。例如:
1977年4月26.4日 UT = JD 2443 259.9
1977年4月26.4日 TD = JDE 2443 259.9
儒略日的计算
设Y为给定年份,M为月份,D为该月日期(可以带小数)。
若M > 2,Y和M不变,若 M =1或2,以Y–1代Y,以M+12代M,换句话说,如果日期在1月或2月,则被看作是在前一年的13月或14月。
对格里高利历有 :A = INT(Y/100) B = 2 - A + INT(A/4)
对儒略历,取 B = 0
要求的儒略日即为:JD = INT(365.25(Y+4716))+INT(30.6001(M+1))+D+B-1524.5

使用数值30.6取代30.6001才是正确的,但我们仍使用30.6001,以确保总能取得恰当的整数。事实上可用30.601甚至30.61来取代30.6001。例如,5乘30.6精确等于153,然而大多数计算机不能精确表示出30.6,这导致得出一个152.999 9998的结果,它的整数部分为152,如此算出的JD就不正确了。


上述计算星期的方法虽然步骤简单,但是每次都要计算两个日期的时间差,不是非常方便。如果能够有一个公式可以直接根据日期计算出对应的星期岂不是更好?幸运的是,这样的公式是存在的。此类公式的推导原理仍然是通过两个日期的时间差来计算星期,只是通过选择一个特殊的日期来简化公式的推导。这个所谓的特殊日期指的是某一年的1231日这天刚好是星期日这种情况。选择这样的日子有两个好处,一个是计算上可以省去计算标准日期这一年的剩余天数,另一个是计算出来的日期差余数是几就是星期几,不需要再计算星期的差值。人们知道公元元年的11日是星期一,那么公元前1年的1231日就是星期日,用这一天作为标准日期,就可以只计算整数年的时间和日期所在的年积累的天数,这个星期公式就是:

 

w = (L * 366 + N * 365 + D) % 7                             (公式 2)

 

公式中的L是从公元元年到ymd日所在的年之间的闰年次数,N是平常年次数,Dy年内的积累天数。将整年数y - 1 = L + N带入上式,可得:

 

w = ( (y - 1) * 365 + L + D) % 7                              (公式 3)

 

根据闰年规律,从公元元年到y年之间的闰年次数是可以计算出来的,即:

L带入公式2,得到星期w的最终计算公式:

还以2005531日为例,利用公式5计算w的值为:

得到2005531日是星期二,和前面的计算方法得到的结果一致。根据上述分析,可得写出使用公式5计算星期的算法实现:

146 int TotalWeek(int year, int month, int day)

147 {

148     int d = CalcYearPassedDays(year, month, day);

149     int y = year - 1;

150     int w = y * DAYS_OF_NORMAL_YEAR + y / 4 - y / 100 + y / 400 + d;

151 

152     return w % 7;

153 }

        公式5的问题在于计算量大,不利于口算星期结果。于是人们就在公式5的基础上继续推导更简单的公式。德国数学家克里斯蒂安·蔡勒(Christian Zeller, 1822- 1899)在1886年推导出了著名的为蔡勒(Zeller)公式:

 

对计算出的w值除以7,得到的余数就是星期几,如果余数是0,则为星期日。蔡勒公式中各符号的含义如下:

:星期;

:世纪数 – 1的值,如21世纪,则 = 20

:月数,的取值是大于等于3,小于等于14。在蔡勒公式中,某年的1月和2月看作上一年的13月和14月,比如200121日要当成2000年的141日计算;

:年份,取公元纪念的后两位,如1998年, = 982001年, = 1

:某月内的日数

 

为了方便口算,人们通常将公式6中的一项改成

。目前人们普遍认为蔡勒公式是计算某一天是星期几的最好的公式。但是蔡勒公式有时候可能计算出的结果是负数,需要对结果+7进行修正。比如200671日,用蔡勒公式计算出的结果是 -1,实际上这天是星期六。根据前面分析的结果整理出的蔡勒公式算法实现如下:

155 int ZellerWeek(int year, int month, int day)

156 {

157     int m = month;

158     int d = day;

159 

160     if(month <= 2) /*对小于2的月份进行修正*/

161     {

162         year--;

163         m = month + 12;

164     }

165 

166     int y = year % 100;

167     int c = year / 100;

168 

169     int w = (+ y / 4 + c / 4 - 2 * c + (13 * (+ 1) / 5) + d - 1) % 7;

170     if(< 0) /*修正计算结果是负数的情况*/

171         w += 7;

172 

173     return w;

174 }

 

        蔡勒公式(公式6)和前面提到的公式5都只适用于格里历法。罗马教皇在1582年修改历法,将105日指定为1015日,从而正式废止儒略历法,开始启用格里历法。因此,上述求星期几的公式只适用于15821015日之后的日期,对于1582年将104日之前的日期,蔡勒也推导出了适用与儒略历法的星期计算公式:

公式7适用于对1582104日之前的日期计算星期,1582105日与15821015日之间的日期是不存在的,因为它们都是同一天。

 

        格里历历法简单,除二月外每月天数固定,二月则根据是否是闰年确定是28天还是29天,每天的星期数可以通过蔡勒公式(公式6)计算,有了这些信息,就可以按照一定的排版格式将某一年的日历打印出来。排版打印的算法非常简单,就是按照顺序打印12个月的月历,因此,打印月历的函数就是输出算法的重点。代码没什么特别之处,就是用一些小技巧确定每个月的第一天的开始位置,打印月历的核心代码如下:

229 void PrintMonthCalendar(int year, int month)

230 {

231     int days = GetDaysOfMonth(year, month); /*确定这个月的天数*/

232     if(days <= 0)

233         return;

234 

235     PrintMonthBanner(nameOfMonth[month - 1]);

236     PrintWeekBanner();

237     int firstDayWeek = ZellerWeek(year, month, 1);

238     InsertRowSpace(firstDayWeek);

239     int week = firstDayWeek;

240     int i = 1;

241     while(<= days)

242     {

243         printf("%-10d", i);

244         if(week == 6) /*到一周结束,切换到下一行输出*/

245         {

246             SetNextRowStart();

247         }

248         i++;

249         week = (week + 1) % 7;

250     }

251 }

 

GetDaysOfMonth()函数其实就是从daysOfMonth表中查一下每月的天数,如果是闰年,则对二月的天数修正(+1),daysOfMonth表定义如下:

 

int daysOfMonth[MONTHES_FOR_YEAR] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

 

计算星期不必对每一天都计算一次,只要对每个月的第一天计算一次就可以了,以后的日期可以用 week = (week + 1) % 7 直接推算出星期几。下面就是我们的算法打印输出的效果:

 

********************************************************************************

 

                              Calendar of 2012

 

********************************************************************************

 

----------January----------

 

Sunday    Monday    Tuesday   Wednesday Thursday  Friday    Saturday

1         2         3         4         5         6         7

8         9         10        11        12        13        14

15        16        17        18        19        20        21

22        23        24        25        26        27        28

29        30        31

 

----------February----------

 

Sunday    Monday    Tuesday   Wednesday Thursday  Friday    Saturday

                              1         2         3         4

5         6         7         8         9         10        11

12        13        14        15        16        17        18

19        20        21        22        23        24        25

26        27        28        29

 

----------March----------

 

Sunday    Monday    Tuesday   Wednesday Thursday  Friday    Saturday

                                        1         2         3

4         5         6         7         8         9         10

11        12        13        14        15        16        17

18        19        20        21        22        23        24

25        26        27        28        29        30        31

 

……

 

 

小知识2儒略历和格里历

在公元15821015日之前,人们使用的历法是源自古罗马的儒略历,儒略历的置闰规则就是四年一闰,但是没有计算每年多出来的0.0078天,这样从公元前46年到公元1582年一共累积多出了10天,为此,当时的教皇格里十三世将1582105日人为指定为1015日,并开始启用新的置闰规则,这就是后来沿用至今的格里历。

 

 

小知识3约化儒略日

由于儒略日数字位数太多,国际天文联合会于19738月决定对其修正,采用约化儒略日(MJD)进行天文计算,定义MJD = JD – 2400000.5MJD相应的起始点是18581117 0:00

 

 

小知识417529月到底是怎么回事儿

如果你用的操作系统是unixlinux,在控制台输入以下命令:

 

#cal 9 1752

 

你会看到这样一个奇怪的月历输出:

 

September 1752

Su Mo Tu We Th Fr Sa

       1  2 14 15 16

17 18 19 20 21 22 23

24 25 26 27 28 29 30

 

1752年的9月缺了11天,到底怎么回事儿?这其实还是因为从儒略历到格里历的转换造成的。1582105日,罗马教皇格里十三世宣布启用更为精确的格里历,但是整个欧洲大陆并不是所有国家都立即采用格里历,比如大英帝国就是直到17529月议会才批准采用格里历,所以大英帝国及其所有殖民地的历法一直到17529月才发生跳变,“跟上”了格里历。德国和荷兰到了1698年才采用格里历,而俄罗斯则直到1918年革命才采用格里历。Linuxcal指令起源与最初AT&TUNIX,当然采用的是美国历法,但是美国历史太短,再往前就只能采用英国历法,所以cal指令的结果就成了这样。对于采用格里历的国家来说,只要知道158210月发生了日期跳变就行了,可以不用关心17529月到底是怎么回事儿。但是对于研究历史和考古的人来说,就必需要了解这个历史,搞清楚每个欧洲国家改用格里历的年份,否则就可能在一些问题上出错。在欧洲研究历史,你会发现很多事件都是有多个时间版本的,比如大科学家牛顿的生日就有两个时间版本,一个是按照儒略历历法的16421225日,另一个是格里历历法的164314日,对于英国人来说,1752年之前都是按照儒略历计算的,所以英国的史书可能会记载牛顿出生在圣诞节,这也没什么可奇怪的。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值