这篇文章主要介绍了python实现公历(阳历)转农历(阴历)的方法,涉及农历算法原理及python日期运算相关操作技巧,需要的朋友可以参考下
本文实例讲述了Python实现公历(阳历)转农历(阴历)的方法。分享给大家供大家参考,具体如下:
两个要点:
1、公历转农历用了查表法(第126行)
2、节气用了天文法?(第176行)
运行图 (背景是hao123万年历)


源代码:
# lunar.py
# 2015/02/27 罗兵
import datetime
class Lunar(object):
#******************************************************************************
# 下面为阴历计算所需的数据,为节省存储空间,所以采用下面比较变态的存储方法.
#******************************************************************************
#数组g_lunar_month_day存入阴历1901年到2050年每年中的月天数信息,
#阴历每月只能是29或30天,一年用12(或13)个二进制位表示,对应位为1表30天,否则为29天
g_lunar_month_day = [
0x4ae0, 0xa570, 0x5268, 0xd260, 0xd950, 0x6aa8, 0x56a0, 0x9ad0, 0x4ae8, 0x4ae0, #1910
0xa4d8, 0xa4d0, 0xd250, 0xd548, 0xb550, 0x56a0, 0x96d0, 0x95b0, 0x49b8, 0x49b0, #1920
0xa4b0, 0xb258, 0x6a50, 0x6d40, 0xada8, 0x2b60, 0x9570, 0x4978, 0x4970, 0x64b0, #1930
0xd4a0, 0xea50, 0x6d48, 0x5ad0, 0x2b60, 0x9370, 0x92e0, 0xc968, 0xc950, 0xd4a0, #1940
0xda50, 0xb550, 0x56a0, 0xaad8, 0x25d0, 0x92d0, 0xc958, 0xa950, 0xb4a8, 0x6ca0, #1950
0xb550, 0x55a8, 0x4da0, 0xa5b0, 0x52b8, 0x52b0, 0xa950, 0xe950, 0x6aa0, 0xad50, #1960
0xab50, 0x4b60, 0xa570, 0xa570, 0x5260, 0xe930, 0xd950, 0x5aa8, 0x56a0, 0x96d0, #1970
0x4ae8, 0x4ad0, 0xa4d0, 0xd268, 0xd250, 0xd528, 0xb540, 0xb6a0, 0x96d0, 0x95b0, #1980
0x49b0, 0xa4b8, 0xa4b0, 0xb258, 0x6a50, 0x6d40, 0xada0, 0xab60, 0x9370, 0x4978, #1990
0x4970, 0x64b0, 0x6a50, 0xea50, 0x6b28, 0x5ac0, 0xab60, 0x9368, 0x92e0, 0xc960, #2000
0xd4a8, 0xd4a0, 0xda50, 0x5aa8, 0x56a0, 0xaad8, 0x25d0, 0x92d0, 0xc958, 0xa950, #2010
0xb4a0, 0xb550, 0xb550, 0x55a8, 0x4ba0, 0xa5b0, 0x52b8, 0x52b0, 0xa930, 0x74a8, #2020
0x6aa0, 0xad50, 0x4da8, 0x4b60, 0x9570, 0xa4e0, 0xd260, 0xe930, 0xd530, 0x5aa0, #2030
0x6b50, 0x96d0, 0x4ae8, 0x4ad0, 0xa4d0, 0xd258, 0xd250, 0xd520, 0xdaa0, 0xb5a0, #2040
0x56d0, 0x4ad8, 0x49b0, 0xa4b8, 0xa4b0, 0xaa50, 0xb528, 0x6d20, 0xada0, 0x55b0, #2050
]
#数组gLanarMonth存放阴历1901年到2050年闰月的月份,如没有则为0,每字节存两年
g_lunar_month = [
0x00, 0x50, 0x04, 0x00, 0x20, #1910
0x60, 0x05, 0x00, 0x20, 0x70, #1920
0x05, 0x00, 0x40, 0x02, 0x06, #1930
0x00, 0x50, 0x03, 0x07, 0x00, #1940
0x60, 0x04, 0x00, 0x20, 0x70, #1950
0x05, 0x00, 0x30, 0x80, 0x06, #1960
0x00, 0x40, 0x03, 0x07, 0x00, #1970
0x50, 0x04, 0x08, 0x00, 0x60, #1980
0x04, 0x0a, 0x00, 0x60, 0x05, #1990
0x00, 0x30, 0x80, 0x05, 0x00, #2000
0x40, 0x02, 0x07, 0x00, 0x50, #2010
0x04, 0x09, 0x00, 0x60, 0x04, #2020
0x00, 0x20, 0x60, 0x05, 0x00, #2030
0x30, 0xb0, 0x06, 0x00, 0x50, #2040
0x02, 0x07, 0x00, 0x50, 0x03 #2050
]
START_YEAR = 1901
# 天干
gan = '甲乙丙丁戊己庚辛壬癸'
# 地支
zhi = '子丑寅卯辰巳午未申酉戌亥'
# 生肖
xiao = '鼠牛虎兔龙蛇马羊猴鸡狗猪'
# 月份
lm = '正二三四五六七八九十冬腊'
# 日份
ld = '初一初二初三初四初五初六初七初八初九初十十一十二十三十四十五十六十七十八十九二十廿一廿二廿三廿四廿五廿六廿七廿八廿九三十'
# 节气
jie = '小寒大寒立春雨水惊蛰春分清明谷雨立夏小满芒种夏至小暑大暑立秋处暑白露秋分寒露霜降立冬小雪大雪冬至'
def __init__(self, dt = None):
'''初始化:参数为datetime.datetime类实例,默认当前时间'''
self.localtime = dt if dt else datetime.datetime.today()
def sx_year(self): # 返回生肖年
ct = self.localtime #取当前时间
year = self.ln_year() - 3 - 1 # 农历年份减3 (说明:补减1)
year = year % 12 # 模12,得到地支数
return self.xiao[year]
def gz_year(self): # 返回干支纪年
ct = self.localtime #取当前时间
year = self.ln_year() - 3 - 1 # 农历年份减3 (说明:补减1)
G = year % 10 # 模10,得到天干数
Z = year % 12 # 模12,得到地支数
return self.gan[G] + self.zhi[Z]
def gz_month(self): # 返回干支纪月(未实现)
pass
def gz_day(self): # 返回干支纪日
ct = self.localtime #取当前时间
C = ct.year // 100 #取世纪数,减一
y = ct.year % 100 #取年份后两位(若为1月、2月则当前年份减一)
y = y - 1 if ct.month == 1 or ct.month == 2 else y
M = ct.month #取月份(若为1月、2月则分别按13、14来计算)
M = M + 12 if ct.month == 1 or ct.month == 2 else M
d = ct.day #取日数
i = 0 if ct.month % 2 == 1 else 6 #取i (奇数月i=0,偶数月i=6)
#下面两个是网上的公式
# http://baike.baidu.com/link?url=MbTKmhrTHTOAz735gi37tEtwd29zqE9GJ92cZQZd0X8uFO5XgmyMKQru6aetzcGadqekzKd3nZHVS99rewya6q
# 计算干(说明:补减1)
G = 4 * C + C // 4 + 5 * y + y // 4 + 3 * (M + 1) // 5 + d - 3 - 1
G = G % 10
# 计算支(说明:补减1)
Z = 8 * C + C // 4 + 5 * y + y // 4 + 3 * (M + 1) // 5 + d + 7 + i - 1
Z = Z % 12
#返回 干支纪日
return self.gan[G] + self.zhi[Z]
def gz_hour(self): # 返回干支纪时(时辰)
ct = self.localtime #取当前时间
#计算支
Z = round((ct.hour/2) + 0.1) % 12 # 之所以加0.1是因为round的bug!!
#返回 干支纪时(时辰)
return self.zhi[Z]
def ln_year(self): # 返回农历年
year, _, _ = self.ln_date()
return year
def ln_month(self): # 返回农历月
_, month, _ = self.ln_date()
return month
def ln_day(self): # 返回农历日
_, _, day = self.ln_date()
return day
def ln_date(self): # 返回农历日期整数元组(年、月、日)(查表法)
delta_days = self._date_diff()
#阳历1901年2月19日为阴历1901年正月初一
#阳历1901年1月1日到2月19日共有49天
if (delta_days = tmp:
delta_days -= tmp
year += 1
tmp = self._lunar_year_days(year)
#计算月
(foo, tmp) = self._lunar_month_days(year, month)
while delta_days >= tmp:
delta_days -= tmp
if (month == self._get_leap_month(year)):
(tmp, foo) = self._lunar_month_days(year, month)
if (delta_days > 4
def _lunar_month_days(self, lunar_year, lunar_month):
if (lunar_year self._get_leap_month(lunar_year) and self._get_leap_month(lunar_year)):
iBit -= 1
if (self.g_lunar_month_day[lunar_year - self.START_YEAR] & (1 24):
return 0.0
stJd = 365.24219878 * (year - 1900) + s_stAccInfo[st] / 86400.0
return base1900_SlightColdJD + stJd
# 测试
def test(ct=None):
ln = Lunar(ct)
print('公历 {} 北京时间 {}'.format(ln.localtime.date(), ln.localtime.time()))
print('{} 【{}】 {}年 {}日 {}时'.format(ln.ln_date_str(), ln.gz_year(), ln.sx_year(), ln.gz_day(), ln.gz_hour()))
print('节气:{}'.format(ln.ln_jie()))
if __name__ == '__main__':
ct = datetime.datetime(2015,2,19,13,0,15)
test(ct)
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











