阴历算法CnCalendar
- 格式:pdf
- 大小:270.65 KB
- 文档页数:9
农历历算和编历规则(2014版)农历又被称为夏历、阴历、旧历、中历、华历,我国已经用了几千年,是东亚传统历法之一。
农历属于一种阴阳历,平均历月等于一个朔望月,设置闰月使平均历年为一个回归年,设置二十四节气以反映季节,所以又有阳历的成分。
至今几乎全世界所有华人及朝鲜、韩国和越南及早期的日本等国家,仍使用农历来推算传统节日如春节、中秋节等节日。
农历还使用干支纪年,因此就每60年重复六十甲子。
如公元1991年称为辛未年,公元2051年也为辛未年。
从汉武帝时期开始,皇帝年号与干支同时使用,以避免重复。
如清同治三年、甲子年。
农历还使用干支纪日。
古代史书上不记月之几日,而记月之干支日,读古代史书就必须查明该月朔日的干支,再按干支纪日法顺推是月之第几日。
中国历朝颁布的历书,历理均大同小异。
编历规则不变、改革的是推算方法。
史上推算农历方法有几十种之多,还好各时期的史书都有收录中国历朝颁行历书的推算方法;史书有收录我在编写《电脑医生万年历》和《福星万年历》(简称程序、下同)时才能还原史实农历。
程序在网上发布后得到广大网友的支持,同时也有网友来信或来电询问古今农历推算方面的问题。
现在我专门把这些常见问题知识写出来。
以飨网友。
程序选用还原的颁行历及使用年限一、农历(又称:夏历、旧历、中历、华历)1、农历历算和编历常用术语黄经:是在黄道座标系统中用来确定天体在天球上位置的座标值、共分成360度、在这个系统天球被黄道平面分割为南北两个半球,太阳移到黄经0度为春分、移到黄经90度为夏至、移到180度为秋分、移到270度时为冬至。
朔日:月球移到地球和太阳中间时的那一天叫朔日。
平朔:用朔望月的平均长度计算、没考虑日月运行的不均等性;缺点:“含有真正的“朔”的当天有时可能会出现在前一月的最后一日(“晦日”、廿九日或卅日),有时会出现在初二”。
定朔:计算考虑了日月运行的不均等性,将含有真正“朔”的当天作为每月的开始。
平气:计算不考虑太阳在黄道上运动快慢不匀,平气两个节气之间的天数15.22天。
一年中哪个月大,哪个月小,年年不同,由计算决定。
一般的,在19年里中设置7个闰月,有闰月的年份全年383天或384天。
1.公历转换农历的算法公历(Gregorian Calendar)与农历(Chinese Lunar Calendar)的转换关系不是一个简单的公式就可以完成,其中的转换比较复杂,原因是农历的制定相当复杂,是根据天文观测进行指定的。
比较常用并且比较简单的公历转换农历算法就是查表方法。
首先要保存公历农历的转换信息:以任何一年作为起点,把从这一年起若干年的农历信息保存起来(在我的C++类中,是从1900年作为起点的。
选择一个起始点的思想十分重要,在下面的干支纪法和二十四节气中也体现到了)。
回想一下,我们平时是怎样来转换公历农历的呢?是查阅历书,历书中有每一天的公历农历,直接一查就可以了。
那么我们可不可以也这样做呢?当然可以,但是这样做要收录每一天的信息,工作量就会很大,所以我们要简化这些信息。
如何简化呢?要保存一年的信息,其实只要两个信息就可以了:(1)、农历每个月的大小;(2//今年是否有闰月,闰几月以及闰月的大小。
用一个整数来保存这些信息就足够了。
具体的方法是:用一位来表示一个月的大小,大月记为1,小月记为0,这样就用掉了12位,再用低四位来表示闰月的月份,没有闰月记为0。
比如说,2000年的信息数据是0x0c960,转化成二进制就是1100100101100000,表示的含义是1、2、5、8、10、11月大,其余月小,低四位为0说明没有闰月。
2001年的农历信息数据是0x0d954,其中的4表示该年闰4月,月份大小信息就是0x0d95,具体的就是1、2、4、5、8、10、12月大,其余月小。
这样就可以用一个数组来保存这些信息。
在我的C++类中是用m_lunarInfo这个数组来保存这些信息的。
下面就是公历转换成农历的具体算法:(1) 计算所求时间到起始年正月初一的天数。
(2) 从起始年份开始,减去每一月的天数,一直到剩余天数没有下一个月多为止。
农历计算标准
农历,也称阴历或农民历,是一种以月亮的运行周期为基础的日历系统。
与阳历(格里高利历)不同,农历根据月亮的位置确定日期,因此每个月的天数会有所不同。
农历的计算标准可以分为两个方面:年份和月份。
年份的计算标准:
- 农历年份采用十干十二支纪年法,其中十干包括甲、乙、丙、丁、戊、己、庚、辛、壬、癸;十二支包括子、丑、寅、卯、辰、巳、午、未、申、酉、戌、亥。
- 干支纪年法采用了天干地支相配的原则,每60年循环一次。
例如,2024年是甲子年(甲为天干中的第一个字,子为地支中的第一个字),下一个甲子年将是2084年。
- 年份的开始点通常是春节,即农历正月初一。
月份的计算标准:
- 农历每个月从新月开始,到下一个新月之前的时间为一个月份。
- 一个农历年一般包含12个或13个月,每个月的长度在29至30天之间变化,根据月亮的运动轨迹而定。
- 闰月是为了调整农历和阳历之间的差异,一般在需要调整的年份中增加一个额外的月份。
闰月的位置可以是任意一个月份,并且使用闰字来表示,如闰四月。
总的来说,农历的计算标准基于天文观测和传统习俗,通过干支纪年法和月亮的运动规律来确定年份和月份。
这种日历系统在中国以及其他一些东亚国家仍然被广泛使用,并且对于农业、节日等方面有着重要的影响。
1。
1、阳历日期推算阴历日期的方法:前已述及阴历日期是以月亮的圆缺为计月单位,其以逢朔为初一,以月望为十五(大月为十六日),以月晦为二十九日(大月为三十日)。
如要知道1984年6月8日是阴历几日?可以利用公式推算阴历日期:设:公元年数-1977(或1901)=4Q+R则:阴历日期=14Q+10.6(R+1)+年内日期序数-29.5n(注:式中Q、R、n均为自然数,R<4)例:1994年5月7日的阴历日期为:1994-1977=17=4×4+1故:Q=4,R=1 则:5月7日的阴历日期为:14×4+10.6(1+1)+(31+28+31+31+7)-29.5n=204.2- 29.5n然后用29.5去除204.2得商数6......27.2,6即是n值,余数27即是阴历二十七日2.公历换算为农历二十四节气在黄道上的位置是固定的,但各年有平年和闰年之分,就使得回归年天数与实际天数不等,每年在日历上可差一天。
这样可以将阴历经过任意整回归年在现在的日历上查到阳历(阳历一年相当阴历的月数为365.2422/29.530588=12.36827个月)。
例如,可先在1995年的日历上查得与(该年)阴历对应的阳历日期,这样就找到了临时落脚点,也就是找到了阴阳互换的关键。
例如,可先以阴历四月初一(日)为引数,在1995年日历上查到对应的阳历为4月30日。
由于已经计算出经过的月数,将经过的月数的尾数(小数)化为日,加在4月30日上,就得到经过(1995-1070)整年数的阳历日期,也就是起始阴历日期对应的阳历日期,即得到了待查的日期为4月30日加上0.64957×29.530588得到(1070年)5月19.1821840日。
这样就得到了所给例子的阴阳历日期换算结果……”。
0.64957月的由来,(1995-1070)×12.36827=11440.64957月已知依泽公生于梁龙德二年(922)六月二十一日,依下表提供的2099年各月初一日的公历月日数,可以算出龙德二年六月二十一日的公历月日数公元2099年农历各月初一日的公历月日(2099-922)×12.36827=1455.45379月余数为0.45379月×29.530588日=13.4O日因2099年五月初一日(包括该年闯二月)在公历6月19日,加上计算所得的13日为龙德二年六月初一日的公历月日,即该年7月2日,则该年农历六月二十一日为该年7月22日。
农历的算法与规则农历,又称阴历、华历、夏历、汉历、中历等,是一种阴阳合历。
它取月相的变化周期即朔望月为月的长度,参考太阳回归年为年的长度,通过设置闰月以使平均历年与回归年相适应。
农历的算法和规则主要包括以下几个方面:1. 月份长度:农历的月份长度并不是固定的,而是根据两次日月合朔的时间间隔来确定的。
如果一个月内只有一次日月合朔,那么这个月的长度就是29天;如果有两次日月合朔,那么这个月的长度就是30天。
此外,如果一个月份内没有中气,那么这个月份会被视为闰月。
2. 闰月:为了调整农历与阳历之间的时间差,农历设置了闰月。
通常情况下,每隔19年就会增加7个闰月。
具体的闰月规则是,从冬至节气所在的月份开始数,如果有13个朔望月出现,那么就需要增加一个闰月。
这个闰月通常是在二月到十月之间选择一个没有中气的月份作为闰月。
3. 岁首:农历的岁首是正月初一,也称为春节。
在农历中,一年的第一天就是正月初一,而不是立春或立夏等节气。
4. 节气:农历的节气分为中气和节气两种。
中气包括雨水、春分、谷雨、小满、大暑、处暑等;节气包括立春、惊蛰、清明、立夏、芒种、小暑等。
在农历中,月份的名称通常是以该月的中气命名的。
5. 置闰法:为了调整农历与阳历之间的时间差,农历采用了置闰法。
具体的置闰方法是,如果一个年份中有13个朔望月出现,那么就需要增加一个闰月。
这个闰月通常是在二月到十月之间选择一个没有中气的月份作为闰月。
如果在一个年份中有超过两个朔望月没有中气,则只有第一个没有中气的朔望月是闰月。
总之,农历的算法和规则是中国古代人民在长期实践中总结出来的,是一种具有悠久历史和科学性的时间计算方法。
中国阴历知识2007年10月16日星期二 10:51阴历,是指用年、月、日计算时间的方法,历法的一类。
阴历亦称月亮历(Lunar calendar),主要根据月亮绕地球运行一周时间为一个月(29.5306天),大月30天,小月29天,一年12个月354天或355天。
中国传统上使用的夏历,实际上是一种阴阳历。
中国的历法与纪年采用阴阳干支三合历;上古时期,根据不同的农业牧业生产情况需要,分别产生过太阳历法和太阴历法。
农历作为中国传统历法,最早源自何时无从考究,据出土的甲骨文和古代中国典籍多有记载,现时阴阳合一的历法规则一般认为源自殷商时期。
从黄帝历法到清朝末期启用西历(公历)始,中国历史上一共产生过102部历法,这些历法中有的曾经对中国文化与文明产生过重大影响,比如夏历、商历、周历、西汉太初历、隋唐大衍历和皇极历等,有的历法虽然没有正式使用过,但对养生、医学、思想学术、天文、数学等起到过重大作用,如西汉末期的三统历和唐朝的皇极历法等。
汉朝以前的古代中国历法以366天为一岁,用“闰月”确定四时和确定岁的终始;已经有日、月、旬和时的时间单位,具备了阴阳历的技术;观察到了五大行星和日月的运动规律,用“闰月”“减差法”来调整时差;历法实施成为重要大事,主要内容之一是“以闰月定四时成岁”和“正闰余”,即确定闰月位置和如何减去多余出来的天数(不是加上缺少的天数),由此来确定年岁的终结和开始。
到了春秋战国时期,由于周朝王室衰落,诸侯各行其是,因此出现多轨制历法,亦即各诸侯和各地部落还有自己的地方历法;秦朝为中国历史上最后一个“以闰月定四时成岁”的历法。
汉朝初期开始中国历法出现了大转折,全国统一历法,历法也成为了一门较为独立的科学技术。
汉武帝责成邓平、唐都、落下闳等人编写了《太初历》,之后刘歆作《三统历》,这两历的重要特点是年岁合一,一年的整数天数是365天,不再之前历法的366天。
以“加差法”替代之前的“减差法”以调整时差,年岁周期起始相当固定,用数学计算就能确定闰月,用不着“考定星历,建立五行”,至此,阴阳五行基本上退出了历法。
【本程序在DEV C++ 4.9.9.2 下编译通过】有关农历的东西有以下几篇文章:计算某天是星期几【C代码】农历算法简介以及公式农历中天干地支的计算【C代码】农历一百年算法(1921~2021)【C语言代码】农历两百年算法(1901~2100)【C语言代码】下面是两百年算法,另外网上也流传着一个很有名气的一百年算法。
农历一百年算法(1921~2021)【C语言代码】下面的三个表格是农历数据表 LunarCalendarTable 的结构。
总共使用了32位整数的0~23位。
#include <time.h>unsigned int LunarCalendarDay;unsigned int LunarCalendarTable[199] = {0x04AE53,0x0A5748,0x5526BD,0x0D2650,0x0D9544,0x46AAB9,0x056A4D,0x 09AD42,0x24AEB6,0x04AE4A,/*1901-1910*/0x6A4DBE,0x0A4D52,0x0D2546,0x5D52BA,0x0B544E,0x0D6A43,0x296D37,0x 095B4B,0x749BC1,0x049754,/*1911-1920*/0x0A4B48,0x5B25BC,0x06A550,0x06D445,0x4ADAB8,0x02B64D,0x095742,0x 2497B7,0x04974A,0x664B3E,/*1921-1930*/0x0D4A51,0x0EA546,0x56D4BA,0x05AD4E,0x02B644,0x393738,0x092E4B,0x 7C96BF,0x0C9553,0x0D4A48,/*1931-1940*/0x6DA53B,0x0B554F,0x056A45,0x4AADB9,0x025D4D,0x092D42,0x2C95B6,0x 0A954A,0x7B4ABD,0x06CA51,/*1941-1950*/0x0B5546,0x555ABB,0x04DA4E,0x0A5B43,0x352BB8,0x052B4C,0x8A953F,0x 0E9552,0x06AA48,0x6AD53C,/*1951-1960*/0x0AB54F,0x04B645,0x4A5739,0x0A574D,0x052642,0x3E9335,0x0D9549,0x 75AABE,0x056A51,0x096D46,/*1961-1970*/0x54AEBB,0x04AD4F,0x0A4D43,0x4D26B7,0x0D254B,0x8D52BF,0x0B5452,0x 0B6A47,0x696D3C,0x095B50,/*1971-1980*/0x049B45,0x4A4BB9,0x0A4B4D,0xAB25C2,0x06A554,0x06D449,0x6ADA3D,0x 0AB651,0x093746,0x5497BB,/*1981-1990*/0x04974F,0x064B44,0x36A537,0x0EA54A,0x86B2BF,0x05AC53,0x0AB647,0x 5936BC,0x092E50,0x0C9645,/*1991-2000*/0x4D4AB8,0x0D4A4C,0x0DA541,0x25AAB6,0x056A49,0x7AADBD,0x025D52,0x 092D47,0x5C95BA,0x0A954E,/*2001-2010*/0x0B4A43,0x4B5537,0x0AD54A,0x955ABF,0x04BA53,0x0A5B48,0x652BBC,0x 052B50,0x0A9345,0x474AB9,/*2011-2020*/0x06AA4C,0x0AD541,0x24DAB6,0x04B64A,0x69573D,0x0A4E51,0x0D2646,0x 5E933A,0x0D534D,0x05AA43,/*2021-2030*/0x36B537,0x096D4B,0xB4AEBF,0x04AD53,0x0A4D48,0x6D25BC,0x0D254F,0x 0D5244,0x5DAA38,0x0B5A4C,/*2031-2040*/0x056D41,0x24ADB6,0x049B4A,0x7A4BBE,0x0A4B51,0x0AA546,0x5B52BA,0x 06D24E,0x0ADA42,0x355B37,/*2041-2050*/0x09374B,0x8497C1,0x049753,0x064B48,0x66A53C,0x0EA54F,0x06B244,0x 4AB638,0x0AAE4C,0x092E42,/*2051-2060*/0x3C9735,0x0C9649,0x7D4ABD,0x0D4A51,0x0DA545,0x55AABA,0x056A4E,0x 0A6D43,0x452EB7,0x052D4B,/*2061-2070*/0x8A95BF,0x0A9553,0x0B4A47,0x6B553B,0x0AD54F,0x055A45,0x4A5D38,0x 0A5B4C,0x052B42,0x3A93B6,/*2071-2080*/0x069349,0x7729BD,0x06AA51,0x0AD546,0x54DABA,0x04B64E,0x0A5743,0x 452738,0x0D264A,0x8E933E,/*2081-2090*/0x0D5252,0x0DAA47,0x66B53B,0x056D4F,0x04AE45,0x4A4EB9,0x0A4D4C,0x 0D1541,0x2D92B5 /*2091-2099*/};int MonthAdd[12] = {0,31,59,90,120,151,181,212,243,273,304,334};int LunarCalendar(int year,int month,int day){int Spring_NY,Sun_NY,StaticDayCount;int index,flag;//Spring_NY 记录春节离当年元旦的天数。
1、公历转换农历的算法公历(Gregorian Calendar)与农历(Chinese Lunar Calendar)的转换关系不是一个简单的公式就可以完成,其中的转换比较复杂,原因是农历的制定相当复杂,是根据天文观测进行指定的。
比较常用并且比较简单的公历转换农历算法就是查表方法。
首先要保存公历农历的转换信息:以任何一年作为起点,把从这一年起若干年的农历信息保存起来。
回想一下,我们平时是怎样来转换公历农历的呢?是查阅历书,历书中有每一天的公历农历,直接一查就可以了。
那么我们可不可以也这样做呢?当然可以,但是这样做要收录每一天的信息,工作量就会很大,所以我们要简化这些信息。
如何简化呢?下面的三个表格是农历数据表LunarCalendarTable的结构。
总共使用了32位整数的0~23位。
6543210表示春节的公历月份表示春节的公历日期1918121731641551461371281191010911812713农历1-13月大小。
月份对应位为1,农历月大(30天),为0表示小(29天)23222120表示当年闰月月份,值为0为则表示当年无闰月。
计算公历日对应的农历日期的方法:先计算出公历日离当年元旦的天数n1,然后查表取得当年的春节日期,计算出春节离元旦的天数n2,二者相减即可算出公历日离春节的天数n3,以后再根据大小月和闰月信息就可以计算n3减去农历的每月天数,减的次数就是农历月份,最后剩余的天数就是农历日。
2、利于泰勒公式巧算星期在应用数学中有一个计算某一天是星期几的公式,这就是泰勒公式。
公式如下:w=[c÷4] - 2c + y + [y÷4] + [26(m+1)÷10] + d - 1,其中w就是所求日期的星期数。
如果求得的数大于(小于)7,就减去(加上)7的倍数,直到余数小于7为止。
式子中c是指公元年份的前两位数字,y是后两位数字,m是月数,d 是日数。
算法系列之⼆⼗:计算中国农历(⼆)(接上篇)所谓的“天⽂算法”,就是利⽤经典⼒学定律推导⾏星运转轨道,对任意时刻的⾏星位置进⾏精确计算,从⽽获得某种天⽂现象发⽣时的时间,⽐如⽇⽉合朔这⼀天⽂现象就是太阳和⽉亮的地⼼黄经(视黄经)差为0的那⼀瞬间。
能够计算任意时刻⾏星位置的⼀套理论就被称为星历表,⽐较著名的星历表有美国国家航空航天局下属的喷⽓推进实验室发布的DE系列星历表,还有瑞⼠天⽂台在DE406基础上拓展的瑞⼠星历表等等。
根据⾏星运⾏轨道直接计算⾏星位置通常不是很⽅便,更何况⼤多数民⽤天⽂计算⽤不上那么多精确的轨道参数,于是天⽂学家在这些星历表的基础上推导出了很多可以做简便计算,但是⼜能保证⼀定精度的⾏星运⾏理论,⽐较著名的有VSOP82/87太阳系⾏星运⾏理论和ELP-2000/82⽉球运⾏理论,这两套理论在精度上已经很接近DE系列星历表了。
关于如何应⽤这两套伦理进⾏天⽂历法计算,请参考“⽇历⽣成算法”系列⽂章的第三篇《⽤天⽂⽅法计算⼆⼗四节⽓》和第四篇《⽤天⽂⽅法计算⽇⽉合朔》,本⽂介绍的农历年历推算是在已经通过天⽂算法获得了精确的节⽓时间和⽇⽉合朔时间的基础上进⾏的。
中国的官⽅纪时采⽤的是中国公历(格⾥历),因此农历年历的推导应以公历年的周期为主导,附上农历年的信息,也就是说,年历以公历的1⽉1⽇为起始,⾄12⽉31⽇结束,根据农历历法推导出的农历⽇期信息,附加在公历⽇期信息上形成双历。
通常情况下,⼀个公历年周期都不能完整地对应到⼀个农历年周期上,⼆者的偏差也不固定,因此不存在稳定的对应关系,也就是说,不存在从公历的⽇期到农历⽇期的转换公式,只能根据农历的历法规则推导出农历⽇期与公历⽇期的对应关系。
由农历历法规则可知,上⼀个公历年的冬⾄()所在的朔望⽉是上⼀个农历年的⼗⼀⽉(冬⽉),所以在进⾏节⽓计算时,需要计算包括上⼀年冬⾄节⽓在内的⼆⼗五个节⽓,才能对应上上⼀个农历年的⼗⼀⽉和当前农历年的⼗⼀⽉。
CnCalendar 历法说明Revision 1.0.1.1作者:刘啸 2006.01.05更新: 2006.09.22一、CnCalendar 介绍CnCalendar 旨在为国内外程序员尤其是 Delphi/C++Builder 程序员提供一开放源码的历 法计算工具包,此包涵盖了公历农历节气干支生肖星座数九三伏出梅入梅日出日落等各个方面,虽 然力求做到完整精确,但历法本身的复杂性和天文现象的不确定性决定了这里的计算不会太完善。
为了给用户一个完整的使用说明以及使用户在发现问题时能通过阅读 CnCalendar 的代码解决问 题,这里将 CnCalendar 的历法算法说明整理如下文。
二、CnCalendar 算法说明本节对 CnCalendar 所使用的算法进行了详细说明,欢迎阅读并指出谬误之处。
1、 概念与常识介绍进行历法计算前,有一些概念是需要首先明确的,包括历法本身的概念、部分天文名词、公历 年、月、日、时的定义等,CnCalendar 算法中所涉及的概念都会在本节中加以说明。
值得一提的 是,部分概念是属于天文现象、部分则是历法推演而来,一般根据前者修正后者。
前后两者拟合的 精确度,是评判历法准确与否的依据。
1)阳历、阴历、阴阳历太阳和月亮是对人类生产活动影响最大的两个天体,因此历法基本上都是以日和(或)月的运 行规矩为依据来计算的,纯粹以太阳的运行规律来计算的历法称为阳历,纯粹以月亮来计算的则称 为阴历,两者兼而有之的自然就是阴阳历了。
公历是典型的阳历,回历是阴历(本文未涉及),中国 的农历则是阴阳历。
2)历理的依据历法的作用有两个,一是能精确计时(或者说是计日),二是要符合实际情况。
这个实际情况包 括很多内容,如季节更替、农耕活动、潮汐涨落等。
实际情况造就了历法,历法反过来又应当能根 据其规则去推演实际情况,这便是历法的最终目的。
目前通用的公历是 1582 年制定的格里高利历 (Gregorian),它在前身儒略历(Julian)的一年 365 日、四年一闰的基础上增加了百年不闰、 四百年又闰的规矩,形成了现在的通用公历历法。
格里高利历是以数值计算为历理依据的,换句话说,按照格里高利历的数值计算规则,可以往前后推任意多的天数而计算出当时的公元年月日来, 至于是否符合实际情况,则只有到时候瞧着办了。
像格里高利历的前身儒略历就出现过硬算下去误 差积累导致春分日提前 10 天的事故,不过令人放心的是,太阳与地球的相对活动情况比较稳定, 儒略历只是拟合得不甚精确,而修改后的格里高利历的精确度提高了许多,至少能支持三千年(如 果加上四千年又不闰的规则则可以撑几万年了)。
这也说明,只要历法所根据的天文情况比较固定, 历法就可能推演成简单数值计算的公式。
公历正是如此。
中国的农历计月所依据的是月亮的运行规则,月亮的不稳定度比太阳高得多,而农历是天文历 法,其原则规定了以实际情况为准、数值计算为辅,所以导致了中国历史上的多次修历,更导致了 目前农历计算和公农历转换的复杂性。
而且农历这个阴阳历还必须考虑到太阳周期(回归年)和月 亮周期(阴历月)的配合,更产生了十九年七闰的规则,而闰月的确定还需要以节气为准,大大增 加了计算的复杂度。
后文会详细说明。
3)春分点,回归年,阴历年地球是斜着绕太阳转的,所以赤道面和黄道面有个固定的夹角,这个夹角在地球公转过程中导 致了太阳直射点在南北回归线间移动,因此造就了四季更替、形成了年的概念。
注意年的概念比发 现地球绕太阳转要久远得多,年对古人的直观感受就是四季更替和春种秋收,这个感受和地球是否 公转是无关的。
假想如果地球光自转不公转而太阳在垂直于黄道面的方向上来回移动,同样也能造 就年的感受。
——说明这点的目的是为了区分下面所描述的概念:恒星年和回归年。
地球精确绕太阳转一周的时间称之为恒星年,而四季更替的精确时间称之为回归年。
那么怎样 衡量四季更替的精确时间?这就要用到春分点的概念。
春分点是天文概念,它是黄道面上的地球公 转轨道和赤道面的两交点之一(另一个自然是秋分点了),春分秋分点时太阳正好直射赤道,而太阳 的直射又正好符合四季更替的感受要求,因此回归年的定义就是地球从这个春分点转一圈又回到春 分点的时间。
如果春分点不动,恒星年就等于回归年,因为地球转一圈又回来了。
遗憾的是地轴总会像陀螺 一样有进动和章动,所以导致的岁差会让春分点在一年中稍微前进一点点,因此一恒星年比一回归 年要长那么一点点,一个是 365.25636 日,一个是 365.2422 日。
记住,回归年才是我们通常 概念中的年。
也许有人要问, 恒星年和回归年有 20 多分钟的差距, 长此累积下去会有什么影响?答案是 “和 历法无关”。
历法中本来就不管地球在公转轨道上的位置,春分点秋分点的平分——冬至点和夏至点 也和公转轨道上的近日点远日点没什么必然关系,所以关心恒星年和回归年的差距是天文学家的事 情。
太阳历的基础就是回归年。
至于阴历年,则没有什么天文意义,只是月的集合而已,不过在农历这个阴阳历中,它也得拟 合回归年的长度。
一农历年是从正月初一到次年正月初一前的时间,它可能包含 12 或 13 个月, 取决于闰年的设定。
农历中还有“岁”的概念,是从冬至日到次年冬至日之间的时间,等于一回归年。
这个概念用 来计算闰月。
4)阳历月,农历月,月朔阳历月同样没有什么天文现象和它对应,设置阳历月只是为了便于把年分割计时,所以儒略历 时能随便将月份的日期调大调小,只要保持一年的天数不变就行。
像七八月连大、二月特小等都是 历史上遗留下来的问题。
农历月则不同,农历的月是阴历月,反映了月相的变化,也就是月球绕地球公转一周的周期。
农历规定了月朔时的那日为农历月首初一,下个月朔时为下个月月首初一。
由于月球的公转周期差 不多是 29.5 天但月必须是天的整数倍,因此农历月有大有小,大月 30 天,小月 29 天,而且 也间隔得无规律可循,也就是说没法在不参考月相又脱离年份的情况下直接算出某个农历月的大小 来,这一点和公历是不同的。
关于月朔也有说明:朔是日月黄经相等的时刻,但由于太阳和月亮运行的不均匀性,导致每两 个相邻月朔之间的时间都不相等,中国唐初以前的农历采用的是经过长期观测统计求得的相邻月朔 间的平均时间,将这个平均时间当成一朔望月,由此直接计算而来的各个月朔时刻称之为平朔。
而 唐初后农历中使用的修正后的比较精确的朔被称为定朔,它们之间是有相对误差的。
5)日及平太阳日日是地球自转带来的昼夜交替,时、分、秒都脱胎于它。
以往日的定义是真太阳日,也就是在 地面上观测到的太阳视点绕地球一周又回到天球上天顶位置的时间间隔,这个间隔和地球精确自转 一周的时间(恒星日)有点差别,因为地球还在公转,位置有点变化,其原理类似于春分日前进导 致的回归年和恒星年的差距。
另外地球的黄赤夹角以及椭圆轨道上的公转速度不均匀也导致了真太“平”在历法中是 阳日的长短在一年中有所区别,为了消除这个差别,历法中引入了平太阳的概念。
指时间均匀分布的意思,平太阳则是一个假想的太阳,以均匀的速度在天球赤道上绕地球运动,其 速度的精确值为真太阳在一回归年内的平均速度,并且和真太阳同时经过近地远地点,这个平太阳 运行一周回到天顶的时间则定义为一平太阳日,也就是现在通常的日的概念。
换句话说,地球一年 内的自转转速分布和公转情况共同决定了一平太阳日的实际大小。
至于时、分、秒,最初都是由平太阳日的定义衍生而来的:1 平太阳日等分为 24 小时,1 小 时等分为 60 分钟, 1 分钟等分为 60 秒。
而后来由于地球自转不均匀导致的平太阳日的精确度不 高,便另起炉灶以其他更精确的手段规定秒的长度,则是以后的事情了。
6)节气节气是对一回归年内地球公转轨道上的 24 个具有季节意义的等分位置的描述, 这 24 个节气 名这里就不赘述了,只是这个“等分”也有说法:中国古代采用平气,按时间等分一回归年,相邻 两节气之间时间间隔固定。
清代修历后改用定气,等分周天为 24 分,每 15°为一个节气,这样 相邻节气的时间间隔由于地球公转速度的变化会有所不同。
24 个节气中包括 12 个节气和 12 个中气,奇数号为节气,存在于每公历月上旬,偶数号为 中气,存在于公历月下旬。
中气对阴历的闰月计算起着决定性的作用。
本文的节气计算和中国现代农历一样使用定气。
而古代使用的平气,其交节时刻和根据定气计算推得的时刻会有较大的误差,计算时应予注意。
7)年月日时的天干地支中国采用天干地支计法来计年月日时,十天干十二地支循环配成六十花甲再轮排,年月日时都 有和其对应的干支。
计算年月日时的干支俗称“算八字” ,当然本文的算八字是指根据年月日时推算 出干支数,并非根据推算出来的四个干支再算命运财运桃花运等,那已经不属于本文讨论的范畴了。
三、历法算法分类介绍在说明算法之前,一些约定俗成的说法需要说明一下:l公元前 n 年表示为 n 年,公元 0 年不存在l不存在公元 1582 年 10 月 5 日到 14 日这 10 天(被 Gregory 删掉了),但星 期和干支仍然连续。
l计算而得的干支、生肖、星座、节气的数字描述均以 0 为起始。
l求回归年内第 N 个节气交节时刻时,第 1 个代表小寒,这里无第 0 个的说法。
CnCalendar 目前的历法算法包括:l星期l公历年月日时的干支l节气的公历交节时刻l星座l公历转农历(部分)l数九三伏入梅出梅l日出日落时刻的计算下面对各个算法分开进行简要说明。
具体实现可以参考 CnCalendar 中的代码,里面也有较 为详尽的注释。
1、计算星期CnCalendar 提供了根据公历年月日计算星期几的方法,算法来源于《新编万年历》一书的公 元日数求余法(有细微修改),原理很简单:星期的 7 天排列是和具体历法无关的,只按照日数循 环计算,因此只要知道某个公历年月日距某个参照日的天数和此参照日的星期数,便可通过 7 求余 法计算出公历年月日的星期几来。
算法中,距公元 1 年 1 月 0 日(公元前 1 年 12 月 31 日) 的日数等于两部分之和:基础年日数和闰年修正日数。
前者等于和公元 1 年的年份差乘以 365 再 加上今年此日距今年 1 月 0 日的日数(包括此日本身,每个闰年里多出的 1 日也计算在内)。
后 者等于年份差对 4 求余再减去个修正值。
年份差是该年和公元 1 年的实际年份差距,当 N 为正 时,公元 N 年的年份差为 N 1,公元前 N 年的年份差为 N(因为无公元 0 年)。
修正值是对 儒略历和格里高利历切换期间的日期调整和对百年不闰四百年又闰规则的调整之和。