python实现的阳历转阴历(农历)算法

时间:2021-05-23


搜索了好几个python实现的万年历多有部分时间有问题,好多是来自这个代码:

复制代码 代码如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Usage: ccal Month [4-Digit-Year]
or: ccal 4-Digit-Year Month

This Python script is to show Solar and Lunar calender at the
same time. You need to have Python (2.0 or above) installed.

Acceptable date range: 1900/2 -- 2049/12

Output contains Chinese characters (mainland GB2312 encoding),
must be viewed in a Chinese-enabled system or "cxterm" etc.
programms under UNIX X-Windows.

The major reference for me to compose this program is:
lunar-2.1.tgz (1992), composed by
Fung F. Lee <lee@umunhum.stanford.edu> and
Ricky Yeung <Ricky.Yeung@Eng.Sun.Com> .

And Lee and Yeung refered to:
1. "Zhong1guo2 yin1yang2 ri4yue4 dui4zhao4 wan4nian2li4"
by Lin2 Qi3yuan2. 《中国阴阳日月对照万年历》.林
2. "Ming4li3 ge2xin1 zi3ping2 cui4yan2" by Xu2 Le4wu2.
《命理革新子平粹言》.徐
3. Da1zhong4 wan4nian2li4. 《大众万年历》

License:
GNU General Public License (GPL, see http://pute the number of days from the Solar First Date
# month=0 means January, ..., year=0 means 1900, ...
def solarDaysFromFirstDate (d): #d is a Date class
return solarDaysFromBaseYear (d) - solarDaysFromBaseYear (solar1st)

def calcLunarDaysPerMonth(iYear):
code = yearCode[iYear]
leapMonth = code&0xf #leapMonth==0 means no lunar leap month

code >>= 4
for iMonth in range(12):
yearInfo[iYear].monthDays[11-iMonth] = lunarMonthDays [code&0x1]
code >>= 1

if leapMonth>0:
yearInfo[iYear].leapMonth = leapMonth-1
yearInfo[iYear].monthDays.insert (leapMonth,
lunarMonthDays [code & 0x1])


def calcAllLunarYearsInfo():
for iYear in range(yearsCoded):
calcLunarDaysPerMonth (iYear)
for iMonth in range(13):
yearInfo[iYear].yearDays += yearInfo[iYear].monthDays[iMonth]


#input dateSolar, return (dateLunar, isLunarMonthOrNot)
def solar2Lunar(d): #d is a Date class
dLunar = Date(-1, -1, -1) #unknown lunar Date class

offset = solarDaysFromFirstDate(d)

dLunar.weekday = (offset + solar1st.weekday)%7

for iYear in range(yearsCoded):
if offset < yearInfo[iYear].yearDays:
dLunar.year = iYear; break
offset -= yearInfo[iYear].yearDays
if dLunar.year == -1: error ("Date out of range.")

dLunar.gan = (dLunar.year + lunar1st.gan) % 10
dLunar.zhi = (dLunar.year + lunar1st.zhi) % 12

for iMonth in range(13):
if offset< yearInfo[dLunar.year].monthDays[iMonth]:
dLunar.month = iMonth; break
offset -= yearInfo[dLunar.year].monthDays[iMonth]

dLunar.day = offset

isLeapMonth=0
if yearInfo[dLunar.year].leapMonth >=0:
if dLunar.month == yearInfo[iYear].leapMonth + 1:
isLeapMonth=1
if dLunar.month > yearInfo[dLunar.year].leapMonth:
dLunar.month -= 1

return (dLunar, isLeapMonth)

def getSolarDaysInMonth (year, month):
if isSolarLeapYear(year) and month==1:
return 29
else: return daysInSolarMonth[month]


def num2GB (num):
if num==10:
return '十'
elif num>10 and num<20:
return '十' + numGB[num-10]

tmp=''
while num>10:
tmp = numGB[num%10] + tmp
num = int(num/10)
tmp = numGB[num] + tmp
return tmp


def lunarDate2GB (dLunar, isLeapMonth):
tmp = str(dLunar.month)+'_'+str(dLunar.day)
if lunarHoliday.has_key( tmp ):
return '%s '% lunarHoliday[tmp] + \
' '*(6-len(lunarHoliday[tmp]))
elif dLunar.day==0:
tmp2 = '闰'*isLeapMonth + num2GB(dLunar.month+1) +'月'
return '%s' % tmp2 + ' '*(8-len(tmp2))
elif dLunar.day<10:
return '初' + num2GB(dLunar.day+1)
else:
return num2GB(dLunar.day+1)


def outputCalendar(year, month):
dLunar = Date(-1,-1,-1)
ow ('\n 阳历%d年%d月 ' % (year+1900, month+1) )

for iDay in range( getSolarDaysInMonth(year, month) ):
dSolar = Date(year, month, iDay)
dLunar, isLeapMonth = solar2Lunar (dSolar)

if iDay==0:
ow ('始于 阴历%s年%s%s月 (%s%s年, 生肖属%s)\n' %
( num2GB(dLunar.year+1900), '闰'*isLeapMonth,
num2GB(dLunar.month+1),
ganGB [dLunar.gan], zhiGB[dLunar.zhi], shengXiaoGB[dLunar.zhi]
))
ow ('='*74 + '\n')
for i in range(7):
ow ("%3s %2s " % (weekdayEn[i][:3], weekdayGB[i]) )
ow('\n\n')
for i in range(dLunar.weekday): ow(' '*11)

elif dLunar.weekday==0: ow('\n')

ow ( "%2d %-8s" %(iDay+1, lunarDate2GB(dLunar, isLeapMonth) ) )
ow('\n\n')


def checkArgv (argv):
argc = len(argv)
if argc==1 or argv[1] in ('-h', '--help'):
print __doc__; exit(0)

#in case people input arguments as "4-digit-year month"
if argc==3 and len(argv[1]) == 4 and len(argv[2]) in (1,2):
argv[1], argv[2] = argv[2], argv[1]


#Get month
month=-1
for iMonth in range(12):
if argv[1].lower() == monthEn[iMonth].lower() or \
argv[1].lower() == monthEn[iMonth][:3].lower():
month = iMonth+1; break
if month==-1:
month = eval(argv[1])

if month<1 or month>12: error ("Month not within 1--12.")

#Get year
if argc==2: year = localtime(time())[0]
else:
if len(argv[2]) != 4: error ("Year must be 4 digits.")
year = eval(argv[2])
if year<1900 or year>= 1900+yearsCoded or (year==1900 and month==1):
error ("Year must be within %d--%d, excluding 1900/1."
% (1900, 1900 + yearsCoded-1) )

return year-1900, month-1

year, month = checkArgv(argv)
calcAllLunarYearsInfo()
outputCalendar(year, month)

这个也有问题(1989年8月的数据转换成农历就有问题)

看了好几个程序,发现实现这个并不需要什么NB的算法(好像也不存在这样的算法)可以直接实现阳历转为阴历的,都是记录了一堆阴历的数据,然后根据和基本时间来算相差几天来计算的,所有阴历数据的正确性决定了这个程序的正确性。

同学给了一个lua的程序,我试了一下,还没有找到错误的,先直接给上程序(直接从lua转成python的,写的比较乱)

复制代码 代码如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import math


def GetDayOf(st):
#–天干名称
cTianGan = ["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
#–地支名称
cDiZhi = ["子","丑","寅","卯","辰","巳","午", "未","申","酉","戌","亥"]
#–属相名称
cShuXiang = ["鼠","牛","虎","兔","龙","蛇", "马","羊","猴","鸡","狗","猪"]
#–农历日期名
cDayName =[
"*","初一","初二","初三","初四","初五",
"初六","初七","初八","初九","初十",
"十一","十二","十三","十四","十五",
"十六","十七","十八","十九","二十",
"廿一","廿二","廿三","廿四","廿五",
"廿六","廿七","廿八","廿九","三十"
]
#–农历月份名
cMonName = ["*","正","二","三","四","五","六", "七","八","九","十","十一","腊"]

#–公历每月前面的天数
wMonthAdd = [0,31,59,90,120,151,181,212,243,273,304,334]
#– 农历数据
wNongliData = [2635,333387,1701,1748,267701,694,2391,133423,1175,396438
,3402,3749,331177,1453,694,201326,2350,465197,3221,3402
,400202,2901,1386,267611,605,2349,137515,2709,464533,1738
,2901,330421,1242,2651,199255,1323,529706,3733,1706,398762
,2741,1206,267438,2647,1318,204070,3477,461653,1386,2413
,330077,1197,2637,268877,3365,531109,2900,2922,398042,2395
,1179,267415,2635,661067,1701,1748,398772,2742,2391,330031
,1175,1611,200010,3749,527717,1452,2742,332397,2350,3222
,268949,3402,3493,133973,1386,464219,605,2349,334123,2709
,2890,267946,2773,592565,1210,2651,395863,1323,2707,265877]

#—取当前公历年、月、日—
wCurYear = st["year"]
wCurMonth = st["mon"]
wCurDay = st["day"]
#—计算到初始时间1921年2月8日的天数:1921-2-8(正月初一)—
#nTheDate = (wCurYear – 1921) * 365 + (wCurYear – 1921)/4 + wCurDay + wMonthAdd[wCurMonth] – 38
nTheDate = (wCurYear – 1921) * 365 + (wCurYear – 1921)/4 + wCurDay + wMonthAdd[wCurMonth-1] – 38
if (((wCurYear % 4) == 0) and (wCurMonth > 2)):
nTheDate = nTheDate + 1

#–计算农历天干、地支、月、日—
nIsEnd = 0
m = 0
while nIsEnd != 1:
#if wNongliData[m+1] < 4095:
if wNongliData[m] < 4095:
k = 11
else:
k = 12
n = k
while n>=0:
nBit = wNongliData[m]
for i in range(n):
nBit = math.floor(nBit/2);

nBit = nBit % 2

if nTheDate <= (29 + nBit):
nIsEnd = 1
break

nTheDate = nTheDate – 29 – nBit
n = n – 1

if nIsEnd != 0:
break
m = m + 1

wCurYear = 1921 + m
wCurMonth = k – n + 1
wCurDay = int(math.floor(nTheDate))
if k == 12:
if wCurMonth == wNongliData[m] / 65536 + 1:
wCurMonth = 1 – wCurMonth
elif wCurMonth > wNongliData[m] / 65536 + 1:
wCurMonth = wCurMonth – 1

print '阳历', st["year"], st["mon"], st["day"]
print '农历', wCurYear, wCurMonth, wCurDay
#–生成农历天干、地支、属相 ==> wNongli–
szShuXiang = cShuXiang[(((wCurYear - 4) % 60) % 12) + 1]
szShuXiang = cShuXiang[(((wCurYear - 4) % 60) % 12) + 1]
zNongli = szShuXiang + '(' + cTianGan[(((wCurYear - 4) % 60) % 10)] + cDiZhi[(((wCurYear - 4) % 60) % 12)] + ')年'
#–szNongli,"%s(%s%s)年",szShuXiang,cTianGan[((wCurYear - 4) % 60) % 10],cDiZhi[((wCurYear - 4) % 60) % 12]);

#–生成农历月、日 ==> wNongliDay–*/
if wCurMonth < 1:
szNongliDay = "闰" + cMonName[(-1 * wCurMonth)]
else:
szNongliDay = cMonName[wCurMonth]

szNongliDay = szNongliDay + "月" + cDayName[wCurDay]
print szNongliDay
#return szNongli .. szNongliDay


def main():
st = {"year": 1989, "mon": 8, "day": 1}
GetDayOf(st)
st1 = {"year": 2013, "mon": 10, "day": 7}
GetDayOf(st1)
st1 = {"year": 2013, "mon": 10, "day": 1}
GetDayOf(st1)
#print("" .. GetDayOf(st))
main()

数据基本上正确了,根据自己的需要改一改程序就可以了。以后有时间在改好一点的。

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章