「两千年中公历转换」数据库介绍
转自:http://www.sinica.edu.tw/~tdbproj/sinocal/lusodoc.html
「两千年中公历转换」数据库介绍 (作者:邱展毅jychiou@sinica.edu.tw) |
编按:「两千年中公历转换」目前已开放给网络上所有用户使用,其位置放在中央研究院首页(Home Page)下的「研究成果及各式信息」内(URL为http://www.sinica.edu.tw/ftms/luso.htm),欢迎有兴趣者上线使用。
前言
对文史方面的研究人员而言,可能经常需要使用中历与公历的对照资料,而目前可以提供中公历对照的工具,不外乎各种万年历对照表或中公历对照表等工具书。这些书少则一、二百页,多则上千页,既不便于携带,更不易快速查询。此外,这些工具书所提供的数据可能并不十分完整,或只能在图书馆内查阅,而无法满足立即查询的需求。
生活在网络与通讯快速发展的信息时代,若能在网络上快速取得中公历对照数据,相信是许多人所企盼的。「两千年中公历转换」即是在这股信息浪潮冲击下的产物,它协助我们快速而方便的取得完整的中公历对照数据。根据我们的了解,这可能是目前涵盖期间最长久,提供讯息最完整的中公历转换程序。其转换的范围由公元元年(西汉平帝元始一年)至公元两千年(民国八十九年),所具备的功能除了可直接由公历日期查询对应的中历朝代、帝号、年号、年干支、年、月、日等信息外,亦可直接以中历之朝代、帝号、年号、年干支、日干支...等数据查询对应的公历日期。除了上述的功能之外,我们特别在两千年中公历转换程序中加入中西对照的「月历功能」【注一】。希望这个程序除了对文史方面的研究人员有所帮助外,亦能满足其他对中公历转换有兴趣者的需求。
制作缘起
由于在协助经济所王业键院士处理清代粮价清单的过程中,需要将明朝末年至清朝末年这段期间的中历日期对照为公历日期。且由于清代粮价清单在中历日期部份需使用「朝代」、「帝号」、「年号」、「年干支」等数据,而目前计算机上并无这类的工具可供使用,因而着手进行中公历转换程序的开发工作。
当设计中公历转换程序时,我们认为与其仅局限于清代两、三百年之间,不如扩充其架构,以整个中国历史期间为标的。这么做程序的复杂度并不会增加太多,且数据结构几乎不需再做调整。因此,我们先依据薛仲三、欧阳颐两位先生所编着的「两千年中公历对照表」建立基本的对照数据,并暂将本程序命名为「两千年中公历转换」。
中国历与西洋历的规则
撰写中公历转换程序时,有必要对中国历法与西洋历法的运算规则与特例作进一步的了解,以期能正确的推算出中公历对应的日期。以下分别说明程序中所使用的运算规则,并介绍几个中国历与西洋历的特例。
一、西洋历的运算规则
西洋历的计算规则较为单纯,主要的重点为闰年的计算。其运算规则为:「公元年被4整除且不被100整除,或被400整除者即为闰年」。此一运算规则是现代人日常生活中耳熟能详的,且经常在许多计算器程序语言的书中被引用。不过,可能少有人注意到西洋历中存在的特例(受皇帝、教皇...等因素的影响),且上述闰年的运算规则亦不是一开始就是如此,而是经过校正调整而来的。根据「两千年中公历对照表」的说法,公历有下列特例:
1.公历4年(该年为闰年:被4整除且不被100整除),因罗马皇帝「奥古斯都帝」停闰,故该年二月只有二十八天,而非二十九天。
2.教皇「格勒哥里第十三」改历,以公元1582年10月5日为15日,中间略过10天,亦即公元1582年少了10/5-10/14这十天。
3.公元1582年以前的闰年计算规则:「被4整除者即为闰年」。所以,公元100年、200年、300年...、1400年、1500年皆为闰年。
4.公元1582年以后的闰年计算规则,即现今大家耳熟能详的「被4整除且不被100整除,或被400整除者」。例如,公元1700年、1800年、1900年皆不是闰年,而公元16年、1984年、1996年皆为闰年。
上述西洋历的特例情况,在两千年中公历转换程序中已能正确处理。不过有一个事件必须在此提出说明:
在UNIX上有一个很方便的公历日期查询工 具--cal指令,在其manual page内有一个注意事项,特别说明公历1752年9月因为闰年校正的关系,将公元1752年9月3日改为9月14日,使得该月份少了11天。读者可以在UNIX上输入下列指令「cal 9 1752」,即可得到下列结果:
September 1752
Sun |
Mon |
Tue |
Wed |
Thu |
Fri |
Sat |
|
|
1 |
2 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
这个情况显然和「两千年中公历对照表」的讲法有出入,两者虽然都有十一天的校正,但分布时间及校正原因则不同。关于这个问题,我们很希望有文献数据可以查证,为何会存在这个差异?若有读者先进知道这个缘由,亦期盼能为笔者解惑。
二、中国历的运算规则
中国历法注重日、月的运行,日蚀与月蚀的推算,五大行星的出没...等,可说是一部融合阳历与阴历精华,且十分精确的天文历法【注二】。
中国历法必须依据二十四节气(与太阳及农作物生长息息相关)、朔望...等要素作推算。由于推算规则我们并不十分清楚,且因中国古代封建王朝的更迭、年号的变化及许多复杂政治因素的影响,使得中国历存在许多特殊情形,必须在程序中以特例的方式处理。基于这些因素,在处理中历部份时,我们并不采取规则推算的方式,改以基本数据配合精简的数据结构,来完成中历数据转换的功能。
以下是我们所整理出从公历1年至公历2000年,这段期间所对应的中国历之特例情形:
1.王莽以西汉孺子婴初始元年十二月为其始建国元年的正月,故西汉孺子婴初始元年少十二月(该年只有1-11月)。
2.西汉淮阳王更始元年,以王莽地皇4年11月为其更始元年之10月,因此西汉淮阳王更始元年有两个10月(中公历转换程序以闰10月来处理第二个10月)。
3.前魏明帝景初元年,以该年之3月为4月,故是年无3月;至景初三年复寅正,因此前魏明帝景初三年有两个12月(中公历转换程序以闰12月来处理第二个12月)。
4.唐武后(武则天)载初一年,以该年之11月为其天授元年的岁首,因此,唐武后载初元年只有10个月(缺11、12两个月)。
5.唐武后久视一年10月复寅正,因此该年有两个11月及两个12月。
6.唐肃宗上元二年,以该年之11月为宝应元年之岁首,故上元二年只有10个月,而宝应元年有两个11月及两个12月。
除了上述之特例外,由于中国之年代久远,历经了多次朝代的分合更迭,因而有所谓的分裂时代(例如:春秋五霸、战国七雄、三国之魏蜀吴、五代十国...)与统一时代(例如:唐、宋、元、明、清)之分。传统史学家以分裂时代的某个王朝为正统(可能有争议?),两千年中公历转换程序循例以「两千年中公历对照表」一书之正统朝代为依据(例如该书视三国时代之魏为正统)。
程序架构与数据结构
两千年中公历转换程序,由三个主要的程序模块所组成,分别为「基本对照数据」、「中公历转换核心程序」及「Web接口程序(HTML与CGI)」,兹分述如下:
一、基本对照数据
两千年中公历数据的对应,若不谨慎思考日期对应的数据结构,可能会耗费大量的磁盘及内存空间。如此,不仅造成空间的浪费,更有可能因大量输出入时间的延迟,而使得程序执行的效率不彰。下例是一个很直觉但占用较多内存空间的方法:
【方法】直接记录中历月日及公历月日的对应。
【范例】中历:清逊帝宣统三年(岁次辛亥)10月10日→公历:公元1911年11月30日。
【使用空间】使用2个字节(byte)的短整数(short integer)变量来储存中历月、日(10月10日)及公历月、日(11月30日),则两千年的中公历数据约需使用 6MB(4*2*365*2000)的内存空间。
基于上述理由,我们仔细评估该以何种数据结构来表示中公历日期的对应关系,下图即是我们使用的结构:
月 |
日 |
闰几月 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
上图记录每个中历年的相关数据,图中共有16个字段,前两个字段(月、日)为中历每年的第一天所对应的公历日期;第三个字段(闰几月)说明该中历年那一个月为闰月;最后十三个字段,分别表示各个中历月份(含闰月)是大月(30天)或小月(29天)。若每个字段皆以2个字节的短整数变量来储存,需使用64KB(2*16*2000)的记忆空间,较之前的方法(6MB)节省了甚多的空间。
由上图的数据结构中,读者也许会觉得奇怪,为何不用记录「年」这个数据?原因很简单,由于中公历之间存在一对一的年序对应关系,可以直接将公元年视为中历年序。所有的中历对照数据依年序自小而大排列,在这个排列顺序上已经隐含了年序的概念。排除年序的结果,导致每笔数据经过程序转换后,可以摆入4bytes的空间内,非常便于程序的操作。我们只需知道中公历转换的起始对照日期(起始公历年、月、日、星期及对应的起始中历年干支、日干支)【注三】,即可依每笔记录的大小月及闰月数据,逐年往后推算出各中历年的第一天所对应的公历日期。例如,两千年中公历转换由西汉平帝元始一年一月一日(公元元年2月11日星期六)开始记录,则其对应的数据结构如下:
2 |
11 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
1 |
0 |
1 |
0 |
1 |
0 |
2 |
1 |
8 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
1 |
2 |
20 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
.
.
.
2 |
5 |
0 |
1 |
1 |
0 |
0 |
1 |
0 |
0 |
1 |
0 |
1 |
1 |
0 |
0 |
「基本对照数据」建立程序,就是要将数据输入者依上述数据结构所输入的每一笔记录(一笔记录储存一个中历年数据),以一个32位的整数(integer)变量来储存,以节省更多的内存空间。下图即是以一个32位的整数来记录中历(农历)民国84年与公历日期的对照关系:
1 |
31 |
8 |
0 |
1 |
1 |
0 |
1 |
0 |
1 |
1 |
0 |
0 |
1 |
0 |
1 |
上图中,前两个字段分别以4个位(可储存数字0~15)及5个位(可储存数字0~31)来储存中历年的第一天所对应的公历月日;第三个字段以4个位(可储存数字0~15)来记录中历年第几个月为闰月(此例为闰八月);第4到第16个字段分别以一个位(0或1)来表示各个月是大月(以1表示)或小月(以0表示)。如此,共使用了26个位,尚余6个位可供未来弹性使用。使用这个结构来储存二千年中公历对照数据,仅需使用8KB(4*2000)的记忆空间,不仅经济实惠,更留给程序更多扩充的弹性。
除了上述数据结构外,还需要两个表格以提供较完整的中公历对照数据,这两个表格为「朝代表」及「朝代年号表」。「朝代表」为中国每个朝代编号,供「朝代年号表」使用;而朝代年号表则记录各个皇帝使用了那些年号及各个年号的起迄时间。稍后在「操作范例」中,读者可以清楚的看出这两个表格所提供的讯息。
二、中公历转换核心程序
这个部分是整个中公历转换的核心部分,由两个主要的软件组件构成,一为负责公历日期差运算的组件,另一个组件负责中历转公历及公历转中历的相关细节。兹分别说明这两个组件的功能:
(一)公历日期差运算
这是一个独立的软件组件,它的主要功能如下:
1.由给定的日期往前或往后推算下一个日期。例如,1995年2月28日往后30天为1995年3月30日,而1995年3月30日往前30天为1995年2月28日。
2.求算二个日期间相差的天数。例如:1909年1月22日至1912年2月18日共经过了1122天(清朝最后一个皇帝溥仪在位的天数)。
3.求算某个月份的最后一天为几号。例如:公元1996年2月的最后一天为29号,公元1997年2月的最后一天为28号。
(二)中公历互转
这个组件架在「公历日期差运算」组件之上,配合「朝代表」、「朝代年号表」及上一节所介绍的「中公历对照基本数据」,完成中历转公历及公历转中历的功能。例如:查询「清光绪甲午年」,所得到的结果为「公元1894年2月6日至公元1895年1月25日」;查询「公元27年4月1日」,所得到的结果为「东汉光武帝建武三年岁次丁亥闰二月六日」。
三、Web接口程序与CGI程序
两千年中公历转换程序设计之初,除了设计中公历转换「核心程序」供清代粮价清单使用外,亦考虑将此功能开放到网络上,供文史研究人员及有兴趣的使用者使用。而目前正值全球信息网(WorldWide Web)盛行之时,图形化的操作环境乃是时势所趋。因此我们选用HTML(Hyper Text Markup Language)制作图形化的输入接口,并配合CGI(Common Getway Connection)程序,将中公历转换的结果,以图形及表格的方式来显示。
程序语言
两千年中公历转换程序是以C++程序语言撰写而成,此程序可以说是由一组独立的软件组件所组装出来的产品。撰写这支程序时,也正是Java程序语言席卷整个信息与电子世界之时。Java由原先被认为只是用来撰写网络上小程序(applet)的语言,蜕变为一个完整的程序语言。据悉,Java程序语言曾针对C++语言的缺点提出许多改良,且在个体导向(Object-Oriented)程序设计方面似乎又表现得较C++语言更为淋漓尽致。因此笔者在撰写本文前,曾试着将两千年中公历转换程序之部份模块以Java程序语言改写,并完成测试与执行。个人深觉只要具有C++语言程序设计经验者,若能掌握住个体导向程序设计的观念,要进入Java语言「程序设计」的领域,应该是一件轻松愉快的事!
操作范例
【图一】即是「两千年中公历转换」之输入画面。图中清楚的切割为上下两个区块。上面的区块为「公历转中历」功能;下面的区块为「中历转公历」功能。这两个功能皆提供两种输出结果,一为文本模式,另一种为表格模式(选取输入画面中的「显示月历」功能),读者可视需求选择所需的功能。
图一 两千年中公历转换程序输入画面
【范例一】查询公元1023年1月所对应的中历日期。
只要在「公历转中历」输入画面中,输入公历年、月数据,并选取「显示月历」功能,即可得到【图二】中公历对照表格。由于公历一个月通常都会跨二个中历月份,使得同一个月可能存在朝代更换、年号变更、岁次(年干支)改变等情形,故在图二上方加上说明文字,用来说明中公历朝代、帝号、年号、岁次等对应关系。例如,本例中以两列文字说明公元1023年1月1日(星期二)相当于「宋真宗干兴1年岁次壬戌12月7日」;公元1023年1月25日(星期五)相当于「宋仁宗天圣1年岁次癸亥1月1日」。
图二 公历为主轴对照月历
【范例二】查询东汉光武帝建武丁亥年对应的公历日期。
【图三】即为以中历为主轴的中西对照月历。由表格中可以清楚的看出东汉光武帝建武丁亥年相当于建武三年,该年闰二月且于十一月十五日跨入公元28年。
图三 中历为主轴的对照年历
【范例三】查询东汉光武帝建武三年闰二月对应的公历日期。
由【图四】可以清楚的看出东汉光武帝建武三年闰二月与公历日期的对应关系。例如:东汉光武帝建武三年闰二月六日相当于公元27年4月1日。
图四 中历为主轴的对照月历
结语
看完上述的介绍后,您是否已迫不急待的想要上网一窥究竟,享受畅游古今中公历转换的乐趣?您可以查一查自己及亲朋好友的出生日期(国历或农历),并确定一下自己是星期几出生的?甚至您也可以拿着族谱依着「两千年中公历转换」仔细对照增补一番。当然如果您是一位专业的文史研究学者,更希望这个程序对您的研究工作能有所帮助。
下一阶段,我们计划将「两千年中公历转换」扩充为可以处理中国所有可考日期与公历日期之间的转换。例如,可以查询商朝盘庚迁殷所对应的公历日期,或公元前1000年相当于中国那个朝代、在位皇帝是谁、是那个年号、岁次(年干支)为何...等等,当然中国各分裂王朝的历法与日期推算亦是我们努力的重点。希望能制作一个功能完整的中公历转换程序,更希望读者先进能多多提供宝贵的意见,以期对文史研究能有更具体的贡献。
致谢
在撰写两千年中公历转换程序时,感谢中心数据处理小组梁怡华小姐细心的建立「两千年中公历基本对照数据」,使得中公历转换程序得以顺利进行。同时要感谢张佩宜小姐仔细的测试中公历转换功能,并提供许多宝贵的意见。在Web接口的制作方面,感谢赖彦丞及张锦堂两位先生提供许多技术支持及改良的意见。此外,更要感谢林晰先生在中公历转换程序制作的过程中细心的指导与鼓励,方使得本文得以顺利完成。
注
一、国立中正大学资工馆工具箱(URL为http://cssun18.cs.ccu.edu.tw/~csiehtml/tools/tools.html)所提供的「新历农历转换」功能,只能作民国以后的中公历转换;而其「万年历」功能,亦只提供西洋历的月历功能。此外,在UNIX上常用的日期查询工具---cal指令,只能作西洋历的查询,并无中公历对照功能。「两千年中公历转换」不仅含盖这两个工具的功能,更提供了以中历为主轴及以公历为主轴的两种「中西对照月历功能」。
二、国立成功大学物理系之「中国天文学发展简史」首页(URL为http://phyhp.phy.ncku.edu.tw/~htsu/astron_chinese/astron_chinese.html),对中国古代天文学的发展、阳历、阴历及二十四节气有概略的说明,有兴趣的读者可自行上网参考。
三、「两千年中公历转换」之起始日期为:公元元年二月十一日星期六,相当于中国历之西汉平帝元始一年岁次辛酉一月一日(日干支为「己未」)。