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

开通VIP,畅享免费电子书等14项超值服

首页

好书

留言交流

下载APP

联系客服

2020.11.10

(接上篇)

图(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.农历日期怎么算?农历日期怎么算? 中国的一种历法,是阴阳历的一种,一般叫作阴历。平年十二个月,大月三十天,小月二十九天,全年354天或355天(一年中哪个月大,哪个月小,年年不同)。由于每年的天数比太阳年约差十一天,所以在十九年里设置七个闰月,有闰月的年份全年383天或384天。又根据太阳的位置,把一个太阳年分成二十四个节气,http://leijing.net/minsu/jieri/297922.html
2.算法系列之二十:计算中国农历(一)农历算法算法系列之二十:计算中国农历(一) 本文介绍了中国农历的历法规则,包括阴阳历的结合、天干地支纪年法、闰月的设置原理以及农历与二十四节气的关系。农历以月相为基础,通过置闰月协调与回归年的差异。天干地支纪年法通过天干(10个)和地支(12个)组合,每60年一个轮回。农历的闰月依据“十九年七闰”或更精确的“中气https://blog.csdn.net/orbit/article/details/9210413
3.中国农历,有详细的阴历算法中国农历,有详细的阴历算法_农历算法,农历算法Et**on 上传43.55 KB 文件格式 rar 这本来是我为一个商业PDA产品开发的日历程序,最近移植于PC机上, 所以算法 和数据部分是用纯C++写的,不涉及MFC,所有的代码都是以短节省存储空间为主要目 的. 很高兴你对这些代码有兴趣,你可以随意复制和使用些代码,唯一有一点小小https://www.coder100.com/index/index/content/id/1356739
4.python中国农历算法python公历转农历python中国农历算法 python公历转农历 一般使用的万年历,只提供距今前后百年的日历。这是因为其所用的计算方法是一种简便的近似计算,适用范围较小。其次,天文学方法计算量大,不适合日常软件使用。但如果要进行历史研究,范围就超出常用日历,本文即实现计算任意日期的农历。https://blog.51cto.com/u_16099335/8948179
5.python实现的阳历转阴历(农历)算法基于python的中国农历&节日实现工具库源码.zip python python python中国农历&节日实现工具库.zip borax~=4.1 使用示例 (Usage) Borax.LunarDate: 中国农历日期 一个支持1900-2100年的农历日期工具库。 本模块的数据和算法参考自项目 jjonline/calendar.js ,部分算法和数据有所修改。 创建日期,日期推算 from datetimehttps://www.iteye.com/resource/weixin_38721119-13777616
6.中国农历发展简史中国农历发展简史 农历,指的是我国的传统历法,又称旧历,夏历.与古巴比伦历,古印度历,犹太历等 历法一样,中国农历属于阴阳合历,即同时兼顾朔望月周期和回归年周期,使每个月符合月 亮盈亏变化,每一年符合春夏秋冬的变化.除此以外,二十四节气和干支纪法也是中国农历 的重要元素和特征.我国自先秦至清末,正式的历法https://www.newsmth.net/bbsanc.php?path=%2Fgroups%2Fsci.faq%2FAstronomy%2Fbw%2Fall2%2Fbk37k%2FM.1275291864.z0&ap=353
7.中国农历(阴历)与阳历(公历)转换与查询工具·majiameng/tools@*字符串加密解密算法 *2.1 HTTP请求工具类 *2.2 中英文装换工具类 *2.3 字符串加密解密算法 *2.4 异步执行 *2.5:date:中国农历(阴历)与阳历(公历)转换与查询工具 *文件日志读写 *字符串处理 *递归数组处理 ###2.1.HttpRequest Class >Use curl implementation request,Support uploading pictures and custom heahttps://github.com/majiameng/tools/commit/abe994405a4cc035da4212c471a8b39362a65613
8.“真太阳时”和”北京时间“已经相关太阳,时间,历法的知识它是明末清初的《时宪历》法,于1645年农历乙酉鸡年(今年是360周年)正式使用的。说了农历的版本,您别认为这是清朝的老黄历了,落后了,请往下看,中国现行的农历,是农历是由我国科学院紫金山天文台利用现今最精确的农历数据算出和排出的,他们使用的是现代先进轨道计算方法计算的,不再是清代的算法了。https://www.douban.com/note/76229594/
9.农历计算方法探秘(农历如何计算)答案:农历,又称阴历或农事历,是中国传统历法之一。它以月亮的阴晴圆缺为基础,结合太阳的运行规律来安排时间。农历的计算方法较为复杂,主要包括以下几个方面: 1.朔望月的计算:农历以朔望月为单位,一个朔望月是指月亮从朔(月相为新月)到下一个朔的时间。平均而言,一个朔望月的长度约为29.5天。为了使农历年与回归https://www.zaixianjisuan.com/jisuanzixun/nonglijisuanfangfatanmi.html
10.你知道按照中国历法(农历)现在是哪年吗?目前万年历和日历基本上按公式二作为农历算法。希望未来能从万年历或日历同时看到中国开元年(农历:4720年)和公元年(公历:2023年)的区别,让更多人直观了解,中西方的历史发展年限。 公式一:公元纪年+2697 天干:黄帝纪元年份数除以10余1为甲,余2为乙,余3为丙,余4为丁,余5为戊,余6为己,余7为庚,余8为辛,余https://m.dianping.com/ugcdetail/149114438?sceneType=0&bizType=29&msource=baiduappugc
11.查询日历与黄历万年历老黄历日历与黄历是我们生活中常用的工具,用来记录时间和安排日程。日历主要用来标记日期,黄历则是根据农历和天干地支等传统的中国农历算法,提供吉凶宜忌等信息。在现代社会,虽然手机和电脑都能提供日历功能,但仍有很多人喜欢使用传统的纸质日历和黄历。 万年历是一种常见的日历形式,它可以显示多年的日期。通过万年历,我们可以https://www.guoxuetop.com/post/11077.html