农历计算方法

Python012

农历计算方法,第1张

计算示例: https://blog.csdn.net/weixin_42763614/article/details/103051262

农历是一种阴阳合历,故而计算农历既需计算阴历使用的合朔,也要计算阳历使用的节气。农历最早使用平气和平朔,但平朔常有一日误差,以日食校验多不合。所以经历法发展改用定朔法。平气也有误差,但难以简单观察到,并且定气法容易打破农历“无中气置闰”的原则,所以在清代以前一直未得采用。直至近代历法发展,基于对精度及合天的要求,不得不重新改定规则。具体见第三点。

所以计算农历需要先找出气朔,计算气朔则需计算太阳和月亮的黄经,现代天文学使用行星历表计算天体位置。python有第三方库提供相关功能,本文提供的算法以PyEphem库为例,利用太阳黄经计算节气,由SolarTerms函数处理,合朔则直接使用库中提供的next_newmoon函数进行计算。

农历固定了一年十二个月,对应12个中气。如果出现13个月,必然有1个月没有中气,称为闰月,因此固定月序的中气也是固定的。对应关系为:

确认这种对应关系,即可分别使用参数i和j来记录合朔次数和中气序号,当某月为无中气月时,次月起对应的中气序仍从上月。

虽然当前农历以雨水作为正月中气,但历法的一些规则和计算实际是从冬至开始,一年的第一个月是十一月。建正只用于确定年干支的起始月。因为历法推算依赖于对天象的观测,特别是确定一年的长度需要测量同一节气相隔的日数,只有冬至或夏至可通过比较前后日的影长方便确定,历法推算从这里开始。但为与物候结合方便农业生产与工作需要,又将正月确定为雨水中气,作为日常生活中年的开始。

程序中的findDZS函数即处理查找岁首的问题。

两个冬至的间隔为回归年长度约365.2422日,朔望月长度约29.53059日,故可能合朔12或13次。平气法时,一气的长度必然大于一朔的长度,所以只会存在一个无中气月。采用定气法后,气长不固定,因此存在一年有多个无中气月或一月有多个中气的情况,所以重新规定(序号越大优先级越高):(见附注)

原1:判断每月是否有中气,没有则置闰。

增2:仅对从冬至月开始的第一个无中气月置闰。

增3:若两个冬至月间合朔仅12次,则不置闰。

是否置闰的根本原则是,保证一年的农历月序数等于12(中气数),多则置闰,从上月序,不足则不闰。具体分析见下表示例。

判断有无中气,即对应j月的中气i在次月或i在上月且i+1气在j+1月。可以比较i中气及i+1中气与j及前后月朔的历日来确定。但可以发现一个性质,若中气出现在上月,则该月起的合朔次数必等于气数,不宜设闰,故而只需判断一项条件,即中气i进入到次月j+1时方可能有闰。

(证明中气在上月时起合朔次数等于气数:令气长为u,朔长为v,有32>u≥v>29,u-v<2.8。设i+1中气距离次年冬至共有m气,i+1月朔距离次年冬至朔共有m月或m+1月,由于冬至月必然有中气,则i+1气必然在雨水或其后,故0≤m≤10。易知vm <= um <vm + v。)

月干支是根据节气判断,一年必然有12个节气,所以它的干支序是每5年循环一次。直接按干支计算,方法是先找任意一年大雪节气的干支,该年对60求余,以本年大雪干支去之,可得0年(公元前1年)的干支丙子,序12,故任意一年的岁首干支为该年加12,所在节气月的干支,则加上节气序再对60求余。也可考虑节气序与地支序是对应的,则可用上述方法计算天干再拼接为干支。

方法一:根据太阳历判断(程序所用方法):

节气日期与在太阳历中相对固定。由于每年节气数与公历月数相同,则每月的节气也是确定的,只需求该节气在月内的日期,每月内该日及以后的日期都为该节气干支,该日前的日期的月干支则为该节气前一干支。

但是,太阳历的岁长与回归年并非完全相等,现行格里历与回归年误差很小,但儒略历未考虑岁差因素,导致节气与月序的对应关系出现变化,需要处理。

方法二:根据太阴历判断:

节气序与地支对应,但不与月建对应,因为可能存在无节气月,所以判断节气月不能直接根据阴历月序处理。

由于大雪不固定在冬至朔以后,可以从立冬开始查找。使用平气法,大致找到公历日期应在的节气,再用定气法比较实际所在节气,得到节气序,最后加上该年年首节气干支即可。

年的干支序按月从正月起算(或有按节气从立春起算)。正月是冬至起的第三个月,所以实际是比较从公历转换得到的农历月是否在寅月后,否即属于上一年。

计算年干支方法与节气干支类似,得0年(公元前1年)的干支庚申,序56,则任意一年干支可知。(或干支分开计算,庚申分别为6和8,以公历年份分别对干(10)支(12)数求余即可)。

2033年虽然有无中气月但仅合朔12次,为了保证一年有12月,故不闰。

2034有2个无中气月,但由于合朔不会超过13次,至少有一个不闰,采取先出现无中气月先闰的原则。注意这个“先”从冬至月开始而非正月。

注:《清史稿·时宪志四》:“求闰月,以前后两年有冬至之月为准。中积十三月者,以无中气之月,从前月置闰。一岁中两无中气者,置在前无中气之月为闰。”

Python中有3种不同的时间表示法

1.时间戳 timestamp  是从1970年1月1日0时0分0秒开始的秒数

2.struct_time    包含9个元素的tuple

3.format time 已经格式化好便于阅读的时间

使用时间需要使用time模块

import time引入time模块

time.time()方法获取当前的时间,以timestamp的形式

>>>time.time()

1576372527.424447

time.localtime()方法:以struct_time的形式获取当前的当地时间

>>>time.localtime()

time.struct_time(tm_year=2019, tm_mon=12, tm_mday=14,

tm_hour=20, tm_min=15, tm_sec=49, tm_wday=5, tm_yday=348, tm_isdst=0)

time.gmtime()方法:以struct_time的形式获取当前的格林尼治时间

从struct_time中获取具体的年月日:

ctime.tm_year  ctime.tm_mon .....

ttm_tm_isdst = 1来告知mktime()现在处于夏令时,明确使用ttm.tm_isdst = 0来告知未处于夏令时

不同时间表示法的转换

struct_time转timestamp: time.mktime(<struct_time>)

timestamp转struct_time: time.localtime(time.time())

表示日期的意思。

Python采用强制缩进的方式使得代码具有较好可读性。而Python语言写的程序不需要编译成二进制代码。

Python的作者设计限制性很强的语法,使得不好的编程习惯(例如if语句的下一行不向右缩进)都不能通过编译。在计算机内部,Python解释器把源代码转换成称为字节码的中间形式,然后再把它翻译成计算机使用的机器语言并运行。

这使得使用Python更加简单。也使得Python程序更加易于移植。