惟有于技术中才能明得真相

Python农历公历转换

出于某种目的需要在农历和公历之间转换,原本是打算直接用现成的,在网上找了一下,大都只能从公历转换成农历,也包含一些我不想要的功能,于是就打算自己写。我的目的很简单,给一个农历日期得出它的公历日期,以及给一个公历日期得出它的农历日期。我主要是参考了Python版的农历日历Calendar里的算法,它不能从农历转换成公历,并且不能处理闰月,另外我觉得这个算法实现得较啰嗦,原本应该可以实现得更简洁一些。它能够计算1901-2050年之间的农历日期,为了将它的计算范围扩大,我又参考了农历两百年算法(1901~2100)用C实现的算法,将里面的数据做了相应地转换。转换之后我发现两者的数据并不一致,Python版的每年月份天数的数据个别年份有误,而C版的1960年闰月数据有误。当然我只比较了1901-2050年的数据,对于2051-2099看的数据因为只有C版里才有所以无从比较,我测试了几组数据没有大的问题。

在我的实现中主要有两个方法,一个是get_lunar_date,它根据公历返回农历,返回是一个四元组(year,month,day,leap),leap为True表示返回的月份在闰月,为False时表示不是闰月。另外一个是get_solar_date,它根据农历返回公历,由于农历存在闰月,可能有一个农历日期对应着两个公历日期,这个方法返回一个数组,如果农历月份为闰月,这个数组会包含两个公历日期,否则只有一个公历日期。这个方法对日期校验并不十分严格,它允许任意月份的天数为30,严格说来某些月份只有29天,例如农历2009年10月只有29天,但get_solar_date也可以接收2009年10月30,即get_solar_date(2009,10,30),它相当于返回农历2009年11月1日的公历日期,如果严格检验地话应当不允许这一情况。对于闰月也是一样,严格地说农历2009年5月30号只对应着一个公历日期,尽管2009年的5月是闰月,但是闰5月没有30号,严格来讲get_solar_date(2009,5,30)应该只返回一个公历日期,但由于对天数的宽松解释,它仍然返回两个公历日期。这种处理在某些情况下可能是不合适的,但由于我的目的是用于生日提醒,如果一个人是农历30号的生日,但某些年份却没有30日,如果严格处理他可能收不到生日提醒,这里宽松处理天数可能反而比较好。

源代码贴在下面,另外由于前面提到的数据问题,我并不能保证它转换出来的結果一定是正确的,但据我的测试結果大致上是没有问题的,即使数据真有问题也只会影响到一小部分日期,误差也只会在一两天内。当然,另一个错误来源于程序BUG,这毋须多说。

源代码:lunar.py

0 评论: