你知道吗,我们平时用的那个寿星公式其实并不太准确?它只能给出二十四节气的日期,而且有时候还会出错。所以,我们决定用香港天文台的数据来计算,这样更精确一些。毕竟,我们用的是阴阳合历,节气准了,农历日期才能准嘛。

你可能觉得,没有数据库,这个项目是不是就不行了?其实不是的,我们依赖的库很少,运行起来特别快,而且提供的内容还特别丰富。我们的主要内容来自于《钦定协纪辨方书》,每一个神煞宜忌都有依据,遵循宜忌等第表,包含民用、御用事宜,而且支持港式(通书配图)八字月柱算法-默认,通书原文文字农历月份算法,具体看demo.py。
这个项目是完全免费的,而且是开源的,长期有人维护。我们可不是搞封建迷信的,宜忌的意义在于民间是将红白事合理分开,避免今日您宴请宾客,邻居办白事情况出现,引起邻里纠纷社会分裂。
特别鸣谢 @DarkmoonRabbit (https://github.com/DarkmoonRabbit)
使用本开源项目的相关产品:
翻黄历 https://www.fanhuangli.com/
万年历-最新专业桌面老黄历 https://apps.apple.com/cn/app/id1555822960
其他与本项目关联项目:
@Crazydear 的版本 https://github.com/Crazydear/Android-Project/tree/main/cnLunar
@jymusic0663 的 flask 版本 https://github.com/jymusic0663/cnlunar/
其他优秀的无依赖农历项目:
@6tail 的 https://github.com/6tail/lunar-python
历法是基于人们生产活动需要,依据太阳、月亮等天象而制订计算时间的方法,根据月亮的周期变化所订立的历法称为阴历,根据太阳在不同季节的位置的周期变化所订立的历法称为阳历。
因为月亮的周期变化较短,观测方式较为简单,所以阴历在世界各地普遍比阳历更早出现,比如我国的上古六历:黄帝历、夏历、殷历、周历、鲁历、颛顼历,古希腊的希腊历等。大约公元前104年至84年,以农耕文化为主的中国西汉,汉武帝刘彻责成邓平、唐都、落下闳等人编写了《太初历》,中国农历经历了第一次重大改革,引入二十四节气正式成为阴阳合历,历法在中国也成为了一门较为独立的科学技术。与之同一时期,公元前46年,罗马统帅凯撒大帝(Gaius Julius Caesar)在希腊数学家兼天文学家索西琴尼的帮助下制订《儒略历》(Julian calendar)取代旧罗马历法,《儒略历》以回归年为基本单位,是一部纯粹的阳历,并在1582年发展成格里历延续至今,即目前在使用的公历。
南北朝时期数学家祖冲之在历法中引入了岁差,将朔望月长度定为29.5309日,将木星公转周期为11.858年(今测为11.862年),对农历进行了第二次改革。清朝汤若望(德国)推出《时宪历》,废除了圭表测影法,把全年分成二十四份,正式采用以太阳在黄道上位置为标准的定气,中国农历最后一次大改革结束并沿用至今。
由于计算机在我国起步较晚,阴阳合历计算方式更为复杂,需要掌握历法、数学、天文学等多学科知识,许多人对中国农历阴阳合历复杂算法不甚了解,在很长一段时间里,多数研发工程师在计算中国农历时都是用“通用寿星公式”[Y*D+C]-L进行节气计算。“通用寿星公式”属于经验公式,实际上是通过寻找一个拟合值C,来不断趋近实际的农历二十四节气,在计算结果不正确时,又套用了“某某年需要加1日,某某年需要减1日”等“特殊情况”校正值,存在农历算法不准情况,且“通用寿星公式”只输出二十四节气内容有限,无法满足用户对农历更为丰富的文化需求。
为符合Python解释型语言的本质,与跨平台脚本、快速开发应用的特性[2],为传达精确计算及Python“胶水”语言的特性,让更多人方便使用,我们将设计一个依赖库少,农历算法清晰,二十四节气精准、功能丰富、基于Python的无数据库农历算法项目,并将其开源到Pypi(https://pypi.org/)上。
二十四节气寿星公式:[Y×D+C]-L。属于经验公式,其中Y取年数的后2位数,D取经验值0.2422,L取Y/4,公历2000年的小寒、大寒、立春、雨水按照20世纪的C值来算,具体C值如图2-1所示:
图2-1 寿星公式查表值及特殊情况表
根据以上情况,经过分析及实际使用,我们发现寿星公式看似公式简单,但实际判断逻辑复杂,在1901-2000年、2000年前四个节气、2000-2100年存在不同的算法值,200年内存在了22个不同年份的矫正值,在使用过程中极容易出错。经过行业调查发现,许多项目都使用了寿星公式进行二十四节气计算,在输出错误的节气日期后,转而影响到了农历阳历部分包括八字月柱表达、每日宜忌等数据的错误。为此,我们希望使用Python设计并实现一个精准清晰、功能多样化的农历综合算法程序,弥补行业内关于农历历法算法及宜忌算法的空白。
方案一,使用几何数学采用15%黄经夹角,计算日地椭圆轨道。在校验过数据与公式差异后,发现地球椭圆形轨道一年内公转速度差异超过7%,地球围绕著太阳作椭圆形公转,其自转轴并非垂直于公转面,而是倾斜约23度。从地球上观察,太阳相对遥远恒星的轨迹被称为“黄道”。概念上,节气是近乎均匀分布于“黄道”上24个位置的时刻。一个循环历时一年,更精确地说是一个“回归年”。[3]我们尝试使用平均值、开普勒第二定律计算行星轨道,计算值和香港天文台数据已经十分贴近了,但依然有差异。
图2-2 椭圆形的地球公转轨道及二十四节气位置[3]
差异主要来源于一下几个方面:(1)地球、月亮、太阳三个天体呈现无法完美预测的三体运动,甚至还包括木星引力影响(虽然引力抵消微弱);(2)太阳本身也在运动,地球和太阳的质量也不是永恒不变的,这就导致地球的恒星年相对稳定,但回归年浮动振荡。
方案二,直接使用香港紫金山天文台《公历农历对照表》。香港天文台提供的天文授时服务,整理1901年至2100年的观测和预测数据得出《公历农历对照表》。历法是严谨的天文科学,脱离了天文观测的历法将失去其科学性,横跨两个世纪的数据足够覆盖多数场景,在科学严谨性与实用性之间找到最佳平衡。
为此,我们选择方案二作为定气数据。
中国传统历法中除“授时”等天文科学部分外,还有大量的“择日”相关社会科学内容。传统文化中设计了很多“神”,“神”的设计并不全是为了封建迷信,比如故人称木星为“岁”,但根据长久的天象观察,发现木星的公转周期并不是完整的12年(今测为11.862年),于是古人们为了节约历法的计算量,便虚拟出一颗与木星轨道相反,周期为十二年的暗星,称“太岁”,即岁神。
中国传统社会有着丰富的社会活动,不同的社会活动赋予的文化含义不同,部分甚至相互对立,比如喜事与丧事。传统中国历法中设计了很多值班的“神”,不同“神”掌管不同的事务,合理地将这些事务归类,就避免邻里之间喜事丧事在同一天举行,极大地减少社会矛盾发生。然而,因社会活动复杂繁多,历法也设计出了极为复杂的算法,有的根据月份,有的根据日期,有的根据季节。
在提供严谨科学的农历服务的同时,我们希望对中国农历的“文化部分”在代码中进行一定程度的传承。除提供历法科学部分外,根据《四库全书 - 钦定协纪辨方书》的内容,我们额外增加黄历传统文化内容转换等,考虑到使用者的便利性,又另外增加西方历法部分功能。
综上,我们将功能解构为:
公历农历转换(数字表达)、二十四节气日期、季节等;
农历八字表达、每日宜忌、十二神、二十八星宿、纳音、七十二物候、时辰、星次、彭祖百忌、中医时辰经络、农历节日等;
星座、公历节日、常见西方节日等。
2017年7月20日,国务院发布《新一代人工智能发展规划》,人工智能正式纳入国家发展战略,并且已经有数个省份将Python纳入到高考体系中。这说明,在未来很长一段时间内,会有越来越多学龄儿童使用到Python编程语言。为此我们应当设计一个能够轻易安装使用,没有额外附加环境条件的历法程序,我们希望它不包含SQL等数据库、不依赖第三方库只依赖Python基础库、可以使用“pip install”命令直接安装,包含一个用例让用户便捷使用。
综上,我们得出如下设计方案:
(1)将农历春节、闰月、二十四节气等数据使用十六进制存储、向量压缩保存在代码中;
(2)仅用到Python基础库;
(3)提供项目用例函数,且有默认值;
(4)将项目发布到Pypi开源平台;
(5)取一个简单容易记住的项目名称。
中国农历英文直译为“Chinese lunar calendar”,在Pypi上遍历不同名称组合及占用情况后,我们选择Python官方推荐的“驼峰命名法”,将我们的程序命名为:“cnLunar”。
我们搭建了一个简易的框架结构来实现设计需求,如图3-1所示:
config.py作为配置扩展使用,用于实现无数据库存放农历、二十四节气、星座等配置信息;
demo.py作为项目用例,在研发过程中用于调试,程序设计完成后用作帮助用户快速上手的代码模板;
holidays.py用于存放公历、农历节日数据;
lunar.py作为核心模块,用于支撑农历历法部分、传统部分、补充部分数据计算输出,并且保留大量《钦定协纪辨方书》原文作为注释,在输出出现差异时矫正结果;
solar24.py用于将200年内的二十四节气数据解压缩,为核心模块提供函数;
tools.py用于存放基础的数据类型转换、数据清洗函数。
图3-1 项目结构图
为减少开发者学习成本,我们将核心算法设计成一个类,对农历的所有数据转换只访问Lunar一个对象,对历法部分、常用传统部分数据在类初始化时生成,非常用传统部分数据、补充部分数据按需计算生成。这样,待项目发布后,用户只需要执行引入cnLunar,并调用Lunar对象初始化,就能在这个对象中获取到所有数据。
为满足传承中国历法的“传统部分”中复杂的历法算法和逻辑关系的需求,我们将根据《钦定协纪辨方书》原文,将“神煞”看做一个对象,设计一种与古文文字描述结构相匹配的脚本,以便支持快速将古文历法算法,快速翻译成Python语言的简易脚本结构。如图3-2。
图3-2 《钦定协纪辨方书》影印版节选[4]
在阅读《钦定协纪辨方书》原文大量章节后,我们总结出以下规律:
(1)对象是有固定名称的;
(2)一个对象是有值班时间的,值班时间和阳历、阴历年月日都有关系,多数对象习惯按月与日的关系排班;
(3)书中的文字一般从正月开始排班,由于农历正月和农历正月八字表达方式“月柱”(农历八字表达方式的第三、四两字,以农历阳历二十四节气分割)有细微差异,农历正月并不完全等于八字正月;
(4)一个对象是没有绝对好坏的,会在宜从事部分事情的同时,不宜从事部分事情;
(5)不同的值班对象是有等级的,存在输出宜忌需要删减调整;
(6)不同时代的宜忌翻译用词不太一样,需要矫正。
根据对古文的抽象分析,我们设计如下脚本结构:
筛选规则尽量使用字符串或者有序列表合集,使用index指针取值,满足上述条件(3),支持传入指针值来源选择农历数字还是农历八字表达数字。执行规则为:判断变量2是否在变量3内。是,则变量1加入到今天的值神清单,变量4加入今日宜事清单,变量5加入今日忌事清单。否,下一步。
比如《钦定协纪辨方书》原文中:“《广圣历》曰:‘岁破者,太岁所冲之辰也。其地不可兴造、移徙,嫁娶、远行,犯者主损财物及害家长,惟战伐向之吉。’”与“《广圣历》曰:‘岁德者,甲德在甲,乙德在庚,丙德在丙,丁德在壬,戊德在戊,己德在甲,庚德在庚,辛德在丙,壬德在壬,癸德在戊。’”[4]这两句可以转化为以下伪代码脚本:
经过对香港天文台《公历与农历对照表》统计数据分析,如果对农历春节、闰月、二十四节气数据进行存储,可以节约计算量,为符合不引入数据库的设计需求,我们将设计二进制数据结构,存储到一个二进制文件中(调试时可以十六进制数的方式先存放于config.py配置结构)中,在需要使用时,使用位移运算符可高效地提取数据。
图3-3香港天文台 - 公
本文由作者笔名:admin 于 2025-03-06 09:36:01发表在本站,原创文章,禁止转载,文章内容仅供娱乐参考,不能盲信。
本文链接: https://www.cjorange.com/wen/7327.html