公历转农历的python实现

大杂烩。作为自己的记录,保存。

 

两个要点

1、公历转农历用了查表法(第126行)

2、节气用了天文法?(第176行)

 

 运行图 (背景是hao123万年历)

 

 

源代码

  1 # lunar.py
  2 # 2015/02/27 罗兵
  3 import datetime
  4
  5 class Lunar(object):
  6     #******************************************************************************
  7     # 下面为阴历计算所需的数据,为节省存储空间,所以采用下面比较变态的存储方法.
  8     #******************************************************************************
  9     #数组g_lunar_month_day存入阴历1901年到2050年每年中的月天数信息,
 10     #阴历每月只能是29或30天,一年用12(或13)个二进制位表示,对应位为1表30天,否则为29天
 11     g_lunar_month_day = [
 12         0x4ae0, 0xa570, 0x5268, 0xd260, 0xd950, 0x6aa8, 0x56a0, 0x9ad0, 0x4ae8, 0x4ae0,   #1910
 13         0xa4d8, 0xa4d0, 0xd250, 0xd548, 0xb550, 0x56a0, 0x96d0, 0x95b0, 0x49b8, 0x49b0,   #1920
 14         0xa4b0, 0xb258, 0x6a50, 0x6d40, 0xada8, 0x2b60, 0x9570, 0x4978, 0x4970, 0x64b0,   #1930
 15         0xd4a0, 0xea50, 0x6d48, 0x5ad0, 0x2b60, 0x9370, 0x92e0, 0xc968, 0xc950, 0xd4a0,   #1940
 16         0xda50, 0xb550, 0x56a0, 0xaad8, 0x25d0, 0x92d0, 0xc958, 0xa950, 0xb4a8, 0x6ca0,   #1950
 17         0xb550, 0x55a8, 0x4da0, 0xa5b0, 0x52b8, 0x52b0, 0xa950, 0xe950, 0x6aa0, 0xad50,   #1960
 18         0xab50, 0x4b60, 0xa570, 0xa570, 0x5260, 0xe930, 0xd950, 0x5aa8, 0x56a0, 0x96d0,   #1970
 19         0x4ae8, 0x4ad0, 0xa4d0, 0xd268, 0xd250, 0xd528, 0xb540, 0xb6a0, 0x96d0, 0x95b0,   #1980
 20         0x49b0, 0xa4b8, 0xa4b0, 0xb258, 0x6a50, 0x6d40, 0xada0, 0xab60, 0x9370, 0x4978,   #1990
 21         0x4970, 0x64b0, 0x6a50, 0xea50, 0x6b28, 0x5ac0, 0xab60, 0x9368, 0x92e0, 0xc960,   #2000
 22         0xd4a8, 0xd4a0, 0xda50, 0x5aa8, 0x56a0, 0xaad8, 0x25d0, 0x92d0, 0xc958, 0xa950,   #2010
 23         0xb4a0, 0xb550, 0xb550, 0x55a8, 0x4ba0, 0xa5b0, 0x52b8, 0x52b0, 0xa930, 0x74a8,   #2020
 24         0x6aa0, 0xad50, 0x4da8, 0x4b60, 0x9570, 0xa4e0, 0xd260, 0xe930, 0xd530, 0x5aa0,   #2030
 25         0x6b50, 0x96d0, 0x4ae8, 0x4ad0, 0xa4d0, 0xd258, 0xd250, 0xd520, 0xdaa0, 0xb5a0,   #2040
 26         0x56d0, 0x4ad8, 0x49b0, 0xa4b8, 0xa4b0, 0xaa50, 0xb528, 0x6d20, 0xada0, 0x55b0,   #2050
 27     ]
 28
 29     #数组gLanarMonth存放阴历1901年到2050年闰月的月份,如没有则为0,每字节存两年
 30     g_lunar_month = [
 31         0x00, 0x50, 0x04, 0x00, 0x20,   #1910
 32         0x60, 0x05, 0x00, 0x20, 0x70,   #1920
 33         0x05, 0x00, 0x40, 0x02, 0x06,   #1930
 34         0x00, 0x50, 0x03, 0x07, 0x00,   #1940
 35         0x60, 0x04, 0x00, 0x20, 0x70,   #1950
 36         0x05, 0x00, 0x30, 0x80, 0x06,   #1960
 37         0x00, 0x40, 0x03, 0x07, 0x00,   #1970
 38         0x50, 0x04, 0x08, 0x00, 0x60,   #1980
 39         0x04, 0x0a, 0x00, 0x60, 0x05,   #1990
 40         0x00, 0x30, 0x80, 0x05, 0x00,   #2000
 41         0x40, 0x02, 0x07, 0x00, 0x50,   #2010
 42         0x04, 0x09, 0x00, 0x60, 0x04,   #2020
 43         0x00, 0x20, 0x60, 0x05, 0x00,   #2030
 44         0x30, 0xb0, 0x06, 0x00, 0x50,   #2040
 45         0x02, 0x07, 0x00, 0x50, 0x03    #2050
 46     ]
 47
 48     START_YEAR = 1901
 49
 50     # 天干
 51     gan = '甲乙丙丁戊己庚辛壬癸'
 52     # 地支
 53     zhi = '子丑寅卯辰巳午未申酉戌亥'
 54     # 生肖
 55     xiao = '鼠牛虎兔龙蛇马羊猴鸡狗猪'
 56     # 月份
 57     lm = '正二三四五六七八九十冬腊'
 58     # 日份
 59     ld = '初一初二初三初四初五初六初七初八初九初十十一十二十三十四十五十六十七十八十九二十廿一廿二廿三廿四廿五廿六廿七廿八廿九三十'
 60     # 节气
 61     jie = '小寒大寒立春雨水惊蛰春分清明谷雨立夏小满芒种夏至小暑大暑立秋处暑白露秋分寒露霜降立冬小雪大雪冬至'
 62
 63     def __init__(self, dt = None):
 64         '''初始化:参数为datetime.datetime类实例,默认当前时间'''
 65         self.localtime = dt if dt else datetime.datetime.today()
 66
 67     def sx_year(self): # 返回生肖年
 68         ct = self.localtime #取当前时间
 69
 70         year = self.ln_year() - 3 - 1 # 农历年份减3 (说明:补减1)
 71         year = year % 12 # 模12,得到地支数
 72         return self.xiao[year]
 73
 74     def gz_year(self): # 返回干支纪年
 75         ct = self.localtime #取当前时间
 76         year = self.ln_year() - 3 - 1 # 农历年份减3 (说明:补减1)
 77         G = year % 10 # 模10,得到天干数
 78         Z = year % 12 # 模12,得到地支数
 79         return self.gan[G] + self.zhi[Z]
 80
 81     def gz_month(self): # 返回干支纪月(未实现)
 82         pass
 83
 84     def gz_day(self): # 返回干支纪日
 85         ct = self.localtime #取当前时间
 86         C = ct.year // 100 #取世纪数,减一
 87         y = ct.year % 100 #取年份后两位(若为1月、2月则当前年份减一)
 88         y = y - 1 if ct.month == 1 or ct.month == 2 else y
 89         M = ct.month #取月份(若为1月、2月则分别按13、14来计算)
 90         M = M + 12 if ct.month == 1 or ct.month == 2 else M
 91         d = ct.day #取日数
 92         i = 0 if ct.month % 2 == 1 else 6 #取i (奇数月i=0,偶数月i=6)
 93
 94         #下面两个是网上的公式
 95         # http://baike.baidu.com/link?url=MbTKmhrTHTOAz735gi37tEtwd29zqE9GJ92cZQZd0X8uFO5XgmyMKQru6aetzcGadqekzKd3nZHVS99rewya6q
 96         # 计算干(说明:补减1)
 97         G = 4 * C + C // 4 + 5 * y + y // 4 + 3 * (M + 1) // 5 + d - 3 - 1
 98         G = G % 10
 99         # 计算支(说明:补减1)
100         Z = 8 * C + C // 4 + 5 * y + y // 4 + 3 * (M + 1) // 5 + d + 7 + i - 1
101         Z = Z % 12
102
103         #返回 干支纪日
104         return self.gan[G] + self.zhi[Z]
105
106     def gz_hour(self): # 返回干支纪时(时辰)
107         ct = self.localtime #取当前时间
108         #计算支
109         Z = round((ct.hour/2) + 0.1) % 12 # 之所以加0.1是因为round的bug!!
110
111         #返回 干支纪时(时辰)
112         return self.zhi[Z]
113
114     def ln_year(self): # 返回农历年
115         year, _, _ = self.ln_date()
116         return year
117
118     def ln_month(self): # 返回农历月
119         _, month, _ = self.ln_date()
120         return month
121
122     def ln_day(self): # 返回农历日
123         _, _, day = self.ln_date()
124         return day
125
126     def ln_date(self): # 返回农历日期整数元组(年、月、日)(查表法)
127         delta_days = self._date_diff()
128
129         #阳历1901年2月19日为阴历1901年正月初一
130         #阳历1901年1月1日到2月19日共有49天
131         if (delta_days < 49):
132             year = self.START_YEAR - 1
133             if (delta_days <19):
134               month = 11;
135               day = 11 + delta_days
136             else:
137                 month = 12;
138                 day = delta_days - 18
139             return (year, month, day)
140
141         #下面从阴历1901年正月初一算起
142         delta_days -= 49
143         year, month, day = self.START_YEAR, 1, 1
144         #计算年
145         tmp = self._lunar_year_days(year)
146         while delta_days >= tmp:
147             delta_days -= tmp
148             year += 1
149             tmp = self._lunar_year_days(year)
150
151         #计算月
152         (foo, tmp) = self._lunar_month_days(year, month)
153         while delta_days >= tmp:
154             delta_days -= tmp
155             if (month == self._get_leap_month(year)):
156                 (tmp, foo) = self._lunar_month_days(year, month)
157                 if (delta_days < tmp):
158                     return (0, 0, 0)
159                 delta_days -= tmp
160             month += 1
161             (foo, tmp) = self._lunar_month_days(year, month)
162
163         #计算日
164         day += delta_days
165         return (year, month, day)
166
167     def ln_date_str(self):# 返回农历日期字符串,形如:农历正月初九
168         _, month, day = self.ln_date()
169         return '农历{}月{}'.format(self.lm[month-1], self.ld[(day-1)*2:day*2])
170
171     def ln_jie(self): # 返回农历节气
172         ct = self.localtime #取当前时间
173         year = ct.year
174         for i in range(24):
175             #因为两个都是浮点数,不能用相等表示
176             delta = self._julian_day() - self._julian_day_of_ln_jie(year, i)
177             if -.5 <= delta <= .5:
178                 return self.jie[i*2:(i+1)*2]
179         return ''
180
181     #显示日历
182     def calendar(self):
183         pass
184
185     #######################################################
186     #            下面皆为私有函数
187     #######################################################
188
189     def _date_diff(self):
190         '''返回基于1901/01/01日差数'''
191         return (self.localtime - datetime.datetime(1901, 1, 1)).days
192
193     def _get_leap_month(self, lunar_year):
194         flag = self.g_lunar_month[(lunar_year - self.START_YEAR) // 2]
195         if (lunar_year - self.START_YEAR) % 2:
196             return flag & 0x0f
197         else:
198             return flag >> 4
199
200     def _lunar_month_days(self, lunar_year, lunar_month):
201         if (lunar_year < self.START_YEAR):
202             return 30
203
204         high, low = 0, 29
205         iBit = 16 - lunar_month;
206
207         if (lunar_month > self._get_leap_month(lunar_year) and self._get_leap_month(lunar_year)):
208             iBit -= 1
209
210         if (self.g_lunar_month_day[lunar_year - self.START_YEAR] & (1 << iBit)):
211             low += 1
212
213         if (lunar_month == self._get_leap_month(lunar_year)):
214             if (self.g_lunar_month_day[lunar_year - self.START_YEAR] & (1 << (iBit -1))):
215                  high = 30
216             else:
217                  high = 29
218
219         return (high, low)
220
221     def _lunar_year_days(self, year):
222         days = 0
223         for i in range(1, 13):
224             (high, low) = self._lunar_month_days(year, i)
225             days += high
226             days += low
227         return days
228
229     # 返回指定公历日期的儒略日(http://blog.csdn.net/orbit/article/details/9210413)
230     def _julian_day(self):
231         ct = self.localtime #取当前时间
232         year = ct.year
233         month = ct.month
234         day = ct.day
235
236         if month <= 2:
237             month += 12
238             year -= 1
239
240         B = year / 100
241         B = 2 - B + year / 400
242
243         dd = day + 0.5000115740 #本日12:00后才是儒略日的开始(过一秒钟)*/
244         return int(365.25 * (year + 4716) + 0.01) + int(30.60001 * (month + 1)) + dd + B - 1524.5
245
246     # 返回指定年份的节气的儒略日数(http://blog.csdn.net/orbit/article/details/9210413)
247     def _julian_day_of_ln_jie(self, year, st):
248         s_stAccInfo =[
249              0.00, 1272494.40, 2548020.60, 3830143.80, 5120226.60, 6420865.80,
250              7732018.80, 9055272.60, 10388958.00, 11733065.40, 13084292.40, 14441592.00,
251              15800560.80, 17159347.20, 18513766.20, 19862002.20, 21201005.40, 22529659.80,
252              23846845.20, 25152606.00, 26447687.40, 27733451.40, 29011921.20, 30285477.60]
253
254         #已知1900年小寒时刻为1月6日02:05:00
255         base1900_SlightColdJD = 2415025.5868055555
256
257         if (st < 0) or (st > 24):
258             return 0.0
259
260         stJd = 365.24219878 * (year - 1900) + s_stAccInfo[st] / 86400.0
261
262         return base1900_SlightColdJD + stJd
263
264
265
266
267 # 测试
268 def test(ct=None):
269     ln = Lunar(ct)
270     print('公历 {}  北京时间 {}'.format(ln.localtime.date(), ln.localtime.time()))
271     print('{} 【{}】 {}年 {}日 {}时'.format(ln.ln_date_str(), ln.gz_year(), ln.sx_year(), ln.gz_day(), ln.gz_hour()))
272     print('节气:{}'.format(ln.ln_jie()))
273
274
275 if __name__ == '__main__':
276     ct = datetime.datetime(2015,2,19,13,0,15)
277     test(ct)

 

时间: 2024-12-02 16:07:06

公历转农历的python实现的相关文章

如何通过JavaScript实现公历转换农历

相信有人会在页面中中选择日期时,需要知道选择日期的农历!如果是Java的话,在后台一下子就可以给转换掉,但是页面上,通过JavaScript来转换的话,不知道大伙儿有没有好的想法呢?刚好,前一段时间来,朋友问了这么一个问题,然后就写了一个demo给她,还行吧!希望能帮到有需要的各位,好啦,直接上代码,不想闲扯: <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"

Calendar-Converter公历和农历互转JavaScript插件使用例子

Calendar-Converter是一个简单的插件,可能只有中文的应用或者网站才会用到这个插件,这个插件的功能就是在公历和农历之间,进行日期时间转换. 使用示例 首先引入插件文件 <script src="js/calendar-converter.js"></script> 然后实例化插件对象,传递一个时间对象 var cc = new CalendarConverter; cc.solar2lunar(new Date(2011, 0, 3)); ---&

python3实现万年历(包括公历、农历、节气、节日)

#!/usr/local/bin/python3 # coding=utf-8 # Created: 20/07/2012 # Copyright: http://www.cnblogs.com/txw1958/ ''' A Chinese Calendar Library in Python ''' import os, io, sys, re, time, datetime, base64 __version__ = "$Rev: 123 $" __all__ = ['LunarD

公历转农历函数

class Program { static void Main(string[] args) { System.Globalization.ChineseLunisolarCalendar chineseLunisolarCalendar = new System.Globalization.ChineseLunisolarCalendar(); DateTime date = DateTime.Now; int year = chineseLunisolarCalendar.GetYear(

纯ASP代码之公历转农历实现(含属相)--例子代码

农历  <!--#includeFile="clsDay.asp"--><%DimobjChinaDayDimsDay,sWeekDay,sChinaDay,sChinaYear,sChinaAniSetobjChinaDay=New ChinaDayCallobjChinaDay.Action("",sDay,sWeekDay,sChinaYear,sChinaDay,sChinaAni)SetobjChinaDay=Nothing'Respon

Andorid 日历控件库,可左右滑动,显示公历,农历,节假日等功能_Android

封面图:  demo效果图   源码目录结构         Features 日历左右滑动. 显示阳历,农历,节假日和二十四节气 实现对某月日期的单选或者多选. 使用步骤 Gradle Dependency Add the library to your project build.gradle   compile 'com.joybar.calendar:librarycalendar:1.0.4' Sample Usage 实现OnPageChangeListener和OnDateClic

PHP实现的汉字拼音转换和公历农历转换类及使用示例_php实例

本文整理了PHP汉字拼音转换和公历农历转换两个功能类文件,非常实用.比如我们查找通讯录可以通过联系人姓名的拼音首字母来查询,可以通过首字母来导航大数据量,可以通过转换拼音来做网站优化等.公农历转化一般用在日历日程安排的项目中,方便农历的节日提醒等等. 1.PHP汉字转拼音 Pinyin.class.php类文件可以将大多数汉字转换成汉语拼音,当然也有个别生僻字不能转换,如果你想转换所有的汉字拼音的话,可能需要再配合一个汉字字库来实现,使用该类文件就基本能满足你的项目需求了.用法: 复制代码 代码

Javascript农历与公历相互转换的简单实例_javascript技巧

如下所示: /**用法 * Lunar.toSolar(2016, 6, 3); 农历转化公历 * Lunar.toLunar(2016, 7, 6); 公历转化农历 */ var Lunar = { MIN_YEAR : 1891, MAX_YEAR : 2100, lunarInfo : [ [0,2,9, 21936], [6,1,30, 9656], [0,2,17, 9584], [0,2,6, 21168], [5,1,26,43344], [0,2,13,59728], [0,2,

Excel中查询生日的公农历重合日

可能好多人因为传统习惯,会过农历生日,于是带来一个好奇的问题,生日到哪一年公农历会重合?一定要查吗?好吧,算你狠,虽然有19年公农历会重合一说,实际上间隔年数也的确接近19倍数,就用"公农历趣味查询.xls"来解惑吧,打开Excel文件之后. 只要在第一处输入农历的年月日以及是否闰月(只有浅绿色的格子可输),会自动算出指定年份到2050年间对应公历,农历是闰月的,次年是按不闰月计算生日的,最后在"重复"列上进行筛选即可,比如农历66年5月17出生的兄弟就比较郁闷了,