算法系列之二十:计算中国农历(二)

图(1)没有闰月情况下朔日与冬至节气关系图

图中上排数字是公历月的编号,黑色圆点代表朔日,黑色三角形代表冬至节气。图(2)显示了2012年有闰月的情况下朔日和冬至的关系:

图(2)有闰月情况下朔日与冬至节气关系图

朔日编号

对应公历日期

月长

月名

1

01:35:39.90

2010-12-06

29

冬月

2

17:02:34.26

2011-01-04

30

腊月

3

10:30:42.67

2011-02-03

正月

4

04:45:59.44

2011-03-05

二月

5

22:32:15.13

2011-04-03

三月

6

14:50:31.79

2011-05-03

四月

7

05:02:32.51

2011-06-02

五月

8

16:53:54.10

2011-07-01

六月

9

02:39:45.06

2011-07-31

七月

10

11:04:06.43

2011-08-29

八月

11

19:08:50.09

2011-09-27

九月

12

03:55:54.64

2011-10-27

十月

13

14:09:40.97

2011-11-25

14

02:06:27.05

2011-12-25

15

15:39:23.99

2012-01-23

表(2)2011年朔望月与公历日期关系表

编号为1和2的两个朔日之间的朔望月是十一月,因为冬至节气落在这个朔望月,其它月的月名依次类推,正月的朔日就是春节。输出公历和农历双历时,以月(公历)为单位,从每月第一天开始,依次判断每一天属于哪个朔望月,确定这一天的农历月名,然后比较这一天和这个朔望月的朔日之间相差几天,记为农历日期。以2011年1月1日为例,这一天在2010年12月6日(2010年农历十一月的朔日)和2011年1月4日之间(2010年农历十二月的朔日),查表(1)可知对应的农历月是十一月,这一天和2010年12月6日相差26天,因此这一天的农历日期就是“廿七”。再以2011年2月3日(春节)这一天为例,查朔望月表得知2月3日属于从2月3日开始的朔望月,这个朔望月的月名是正月,而2月3日就是月首,农历日期是初一,正月初一就是春节。

5doubleCalculateSolarTerms(intyear,intangle);

8doubleCalculateMoonShuoJD(doubletdJD);

生成指定公历年份的公历和农历的双历年历的流程如下:

图(3)计算公农历双历年历的流程

139voidCChineseCalendar::GetAllSolarTermsJD(intyear,intstart,double*SolarTerms)

140{

141inti=0;

142intst=start;

143while(i<25)

144{

145doublejd=CalculateSolarTerms(year,st*15);

147if(st==WINTER_SOLSTICE)

148{

149year++;

150}

151st=(st+1)%SOLAR_TERMS_COUNT;

152}

153}

start参数是节气的索引,定义二十四节气的索引如下:

38constintVERNAL_EQUINOX=0;//春分

39constintCLEAR_AND_BRIGHT=1;//清明

40constintGRAIN_RAIN=2;//谷雨

41constintSUMMER_BEGINS=3;//立夏

42constintGRAIN_BUDS=4;//小满

43constintGRAIN_IN_EAR=5;//芒种

44constintSUMMER_SOLSTICE=6;//夏至

45constintSLIGHT_HEAT=7;//小暑

46constintGREAT_HEAT=8;//大暑

47constintAUTUMN_BEGINS=9;//立秋

48constintSTOPPING_THE_HEAT=10;//处暑

49constintWHITE_DEWS=11;//白露

50constintAUTUMN_EQUINOX=12;//秋分

51constintCOLD_DEWS=13;//寒露

52constintHOAR_FROST_FALLS=14;//霜降

53constintWINTER_BEGINS=15;//立冬

54constintLIGHT_SNOW=16;//小雪

55constintHEAVY_SNOW=17;//大雪

56constintWINTER_SOLSTICE=18;//冬至

57constintSLIGHT_COLD=19;//小寒

58constintGREAT_COLD=20;//大寒

59constintSPRING_BEGINS=21;//立春

60constintTHE_RAINS=22;//雨水

61constintINSECTS_AWAKEN=23;//惊蛰

137voidCChineseCalendar::GetNewMoonJDs(doublejd,double*NewMoon)

138{

139for(inti=0;i

141doubleshuoJD=CalculateMoonShuoJD(jd);

142NewMoon[i]=shuoJD;

143

145}

146}

170boolCChineseCalendar::BuildAllChnMonthInfo()

171{

172CHN_MONTH_INFOinfo;//一年最多可13个农历月

173inti;

174intyuejian=11;//采用夏历建寅,冬至所在月份为农历11月

175for(i=0;i<(NEW_MOON_CALC_COUNT-1);i++)

176{

177info.mmonth=i;

178info.mname=(yuejian<=12)yuejian:yuejian-12;

179info.shuoJD=m_NewMoonJD[i];

180info.nextJD=m_NewMoonJD[i+1];

181info.mdays=int(info.nextJD+0.5)-int(info.shuoJD+0.5);

182info.leap=0;

183

184CChnMonthInfocm(&info);

185m_ChnMonthInfo.push_back(cm);

186

187yuejian++;

188}

189

190return(m_ChnMonthInfo.size()==(NEW_MOON_CALC_COUNT-1));

191}

194voidCChineseCalendar::CalcLeapChnMonth()

195{

196assert(m_ChnMonthInfo.size()>0);/*阴历月的初始化必须在这个之前*/

197

198inti;

199

200if(int(m_NewMoonJD[13]+0.5)<=int(m_SolarTermsJD[24]+0.5))//第13月的月末没有超过冬至,说明今年需要闰一个月

201{

202//找到第一个没有中气的月

203i=1;

204while(i<(NEW_MOON_CALC_COUNT-1))

205{

206

207/*m_NewMoonJD[i+1]是第i农历月的下一个月的月首,本该属于第i月的中气如果比下一个月

208的月首还晚,或者与下个月的月首是同一天(民间历法),则说明第i月没有中气*/

209if(int(m_NewMoonJD[i+1]+0.5)<=int(m_SolarTermsJD[2*i]+0.5))

210break;

211i++;

212}

213if(i<(NEW_MOON_CALC_COUNT-1))/*找到闰月,对后面的农历月调整月名*/

214{

215m_ChnMonthInfo[i].SetLeapMonth(true);

216while(i<(NEW_MOON_CALC_COUNT-1))

217{

218m_ChnMonthInfo[i++].ReIndexMonthName();

219}

220}

221}

222}

从理论上讲,本文介绍的算法在精度允许的范围内可以计算前后几千年的农历年历,但是对古代的农历计算需要小心。首先是“平朔”和“定朔”的问题,唐代以前使用的是平朔方法定月首,本文介绍的计算方法采用的是“定朔”方法,因此计算出的年历与唐代以前的历史会不一致。另外,即是在唐代以后采用“定朔”的历法,因为古代天文观测和计算受条件限制,可能不够精确,因此与现在用天文算法计算出的结果可能并不一致。所以对历史农历的计算应该以历史事实为主,天文计算为辅,当计算与历史不一致时,要根据历史数据进行校正。Calendar.exe是根据本文介绍的算法编写的日历小程序,没有太多的功能,主要是为了验证算法,因为没有历史数据用于修正结果,因此不支持1601年以前的农历计算(也就是说按照天文算法计算出来的结果可能和实际历史上的历法不符)。

图(5)演示程序的界面

小知识1:民间历法和历理历法

小知识2:通式寿星公式

“通式寿星公式”是前人整理出来的一个用于计算每年立春日期的经验公式:

Date=向下取整(Y*D+C)-L

其中,Y是年份,D的值是0.2422,C是经验值,取决于节气和年份,对于21世纪,立春节气的C值是4.475,春分节气的C值是20.646等等;

L是闰年数,其计算公式为:

L=向下取整(Y/4)-向下取整(Y/100)+向下取整(Y/400)

用“通式寿星公式”确定2011年立春日期的过程如下:

L=int(2011/4)–int(2011/100)+int(2011/400)=502–20+5=487

Date=int(2011×0.2422+4.475)-487=491–487=4

所以,2011年的立春日期是2月4日。

小知识3:计算节气和朔日的经验公式

F=365.242*(y–1900)+6.2+15.22*x-1.9*sin(0.262*x)

其中x是节气的索引,0代表小寒,1代表大寒,其它节气按照顺序类推。

计算从1900年开始第m个朔日的公式是:

M=1.6+29.5306*m+0.4*sin(1-0.45058*m)

小知识4:平朔和定朔

小知识5:正月初一和立春节气

立春是二十四节气之首,所以古代民间都是在“立春”这一天过节,相当于现代的春节(中国古代即是节气也是节日的情况很多,比如清明、冬至等等)。1911年,孙中山领导的辛亥革命建立了中华民国,在从历法上正式把农历正月初一定为“春节”,把公历1月1日定为“元旦”,也就是“新年”。农历年从正月初一开始没有争议,但是农历生肖年从何时开始却一直有争议,目前多数人都认为“立春”节气是农历生肖年的开始。因为在中国古代历法中,十二生肖的计算与天干地支有很大关系,所以在“论天干地支、计算廿四节气”的情况下,“立春”节气应该是新生肖的开始。对于普通老百姓来说,习惯于认为正月初一是生肖年的开始,因此,正月初一和“立春”节气之间出生的小孩,在确定属相的时候就有点麻烦了。属龙还是属蛇?这是个问题。

THE END
1.公历农历转换农历,又称夏历、阴历、旧历,是东亚传统历法之一。农历属于一种阴阳历,平均历月等于一个朔望月,但设置闰月以使平均历年为一个回归年,设置二十四节气以反映季节(太阳直射点的周年运动)的变化特征,所以又有阳历的成分。至今几乎全世界所有华人及朝鲜、韩国和越南及早期的日本等国家,仍使用农历来推算传统节日如春节、中https://gonglinongli.bmcx.com/
2.农历计算方法探秘(农历如何计算)问题:农历 如何计算 答案: 农历,又称阴历或农事历,是中国传统历法之一。它以月亮的阴晴圆缺为基础,结合太阳的运行规律来安排时间。农历的计算方法较为复杂,主要包括以下几个方面: 1.朔望月的计算:农历以朔望月为单位,一个朔望月是指月亮从朔(月相为新月)到下一个朔的时间。平均而言,一个朔望月的长度约为29.5https://www.zaixianjisuan.com/jisuanzixun/nonglijisuanfangfatanmi.html
3.atitit.农历的公式与原理以及农历日期运算所以只要有完整的农历推算公式即可从时间戳换算到农历。 3.农历的公式 有人说农历没有精确的公式,这是错误的,农历有精确的公式,不然怎么推算出来未来的万年历呢。。 农历历月的天数只有29日和30日两种 农历的大小月是完全不固定的,这就使得大小月的安排不固定,而需要通过严格的月相观测和计算来确定。因此,农历中https://blog.csdn.net/attilax/article/details/52180793/
4.日柱公式是什么日柱干支推算口诀日柱公式是什么 日柱干支推算口诀 日柱,即用农历的干支代表人出生的那一天。 什么是日柱公式呢?日柱公式的用途是什么?快到华易网一起和小编了解更多关于八字日柱的内容吧。 日柱公式是什么 “日柱公式”指的是用来换算公历日期与日干支的一种历法公式。 目前,人们普遍使用的公历也就是格里历,是一种太阳历。我国过去https://www.k366.com/bazi/193937.htm
5.农历算法简介以及公式理想股票技术论坛农历算法是用来计算农历日期的一种数学计算方法,它基于中国传统农历的规律和周期性。本文简要介绍了农历算法的基本原理和公式,帮助读者了解如何根据公历日期计算对应的农历日期。 ,理想股票技术论坛https://www.55188.com/tag-04147196.html
6.准确率100生男生女公式汇总,四九法遇闰月这样算才准!怀孕月份双乘法是指假设女性怀孕时月份是农历6月,孕妇的农历生日月份是7月,虚岁年龄为29岁,代入生男生女计算公式:怀孕农历月份双乘+母亲农历生日月份-怀孕时虚龄+19,得出结果数33,尾数为单,说明可能是男孩。 按月推算生男生女公式 在民间流传着清宫图生男生女表,从表中可以发现,不同的年龄和月份对应生男孩或生https://www.born123.com/article/95885a0b5fe67c6e8226.html
7.农历预产期怎么算公式是,末次月经的月份加9或者减3,日数加7,如果是农历,一般需要日数加15,就可以推算预产期的https://www.yilianmeiti.com/question/2976674.html
8.日常生活中最常用的计算公式.pdf鞋码的换算公式 国家发改委于2005年3月19日发布《皮鞋新标准》,即中华人民共和国 轻工行业标准QB/T1002-2005,此标准于2005年9月1日起实施。标准中 对皮鞋类产品的鞋号进行了统一,并规定对于未按标准标注以毫米为单位的 鞋号的皮鞋类产品一律判为不合格产品。新标准替代原有的胶粘皮鞋、硫化 皮鞋、缝制皮鞋、模https://max.book118.com/html/2019/0114/8052077105002001.shtm
9.全新的Excel公农历转换方法,含节气四柱日期计算和天数计算2、EXCEL中是否有公式可以直接推算出农历,就如同之前提供的那份1900-9999年阳历日历,在表中只要点击https://club.excelhome.net/thread-1281548-7-1.html
10.如何准确推算年干支的简单方法命理四柱注:此公式适用于任何年代的天干推算。②推算地支公式(按不同世纪推算):◎十九世纪(即1800~1899年)地支推算公式。公元年末二位数一年支的代数(即年支序号,以下同);◎二十世纪(即1900~1999年)地支推算公式。公元年末二位数+1一年支的代数;◎二十一世纪(即2000~2099年)地支推算公式。公元年末二位数+5一年支的https://www.dadaojiayuan.com/mlsz/39480.html