├── Lunar.py ├── README.md └── read.txt /Lunar.py: -------------------------------------------------------------------------------- 1 | #encoding:utf-8 2 | # by chaseey 3 | import lunardate 4 | import datetime 5 | import math 6 | 7 | # 使用lunardate模块,限制阳历日期范围为1900至2049年.超出范围出错. 8 | 9 | 10 | 11 | 12 | JIE_QI = { 13 | 1:u"立春",2:u"雨水",3:u"惊蛰",4:u"春分",5:u"清明",6:u"谷雨",7:u"立夏",8:u"小满",9:u"芒种",10:u"夏至",11:u"小暑",12:u"大暑", 14 | 13:u"立秋",14:u"处暑",15:u"白露",16:u"秋分",17:u"寒露",18:u"霜降",19:u"立冬",20:u"小雪",21:u"大雪",22:u"冬至",23:u"小寒",24:u"大寒" 15 | } 16 | 17 | # 推算节气, 默认返回立春 OUT:阳历 18 | # 以1899年12月31日(星期日)为基准日, 之后每一天与之差值为积日 19 | # F = 365.242 * (y – 1900) + 6.2 + 15.22 *x - 1.9 * sin(0.262 * x) 误差 0.05天左右 20 | # 计算第x个节气公式 x = [1,2,3,4,5,...........24] 21 | # [小寒,大寒,立春..... ] 22 | def getJieqi(year,x=3): 23 | # 基准日 24 | if x not in range(1,25): 25 | return None 26 | try: 27 | year = int(year) 28 | x = int(x) 29 | except: 30 | return None 31 | if year < 1900: 32 | return None 33 | x -= 1 34 | startDT = datetime.datetime(1899,12,31) 35 | # 相差的天数 36 | days = 365.242*(year - 1900) + 6.2 + 15.22*x - 1.9*math.sin(0.262*x) 37 | delta = datetime.timedelta(days=days) 38 | return startDT+delta 39 | 40 | 41 | 42 | # 取得当年全年的节气时间列表. 43 | def getJieqiList_byYear(year,jie_only=False,qi_only=False,addNum=False): 44 | # addNum 加上节气对应的序号 45 | try: 46 | year = int(year) 47 | except: 48 | return [] 49 | res = [] 50 | if jie_only and qi_only: # 两者相排斥 51 | raise KeyError 52 | if jie_only: 53 | for i in range(1,25,2): 54 | if addNum: 55 | res.append((getJieqi(year,x=i),i)) 56 | else: 57 | res.append(getJieqi(year,x=i)) 58 | elif qi_only: 59 | for i in range(2,25,2): 60 | if addNum: 61 | res.append((getJieqi(year,x=i),i)) 62 | else: 63 | res.append(getJieqi(year,x=i)) 64 | else: 65 | for i in range(1,25): 66 | if addNum: 67 | res.append((getJieqi(year,x=i),i)) 68 | else: 69 | res.append(getJieqi(year,x=i)) 70 | return res 71 | 72 | 73 | # 取得某年某月的节气. 74 | def getJieqiList_byMonth(year,month,jie_only=False,qi_only=False,addNum=False): 75 | try: 76 | year = int(year) 77 | month = int(month) 78 | except: 79 | return [] 80 | jieqiList = getJieqiList_byYear(year,jie_only=jie_only,qi_only=qi_only,addNum=addNum) 81 | res = [] 82 | if addNum: 83 | for dt,num in jieqiList: 84 | if dt.month == month: 85 | res.append((dt,num)) 86 | else: 87 | for dt in jieqiList: 88 | if dt.month == month: 89 | res.append(dt) 90 | if len(res) == 0: 91 | raise KeyError 92 | return res 93 | 94 | 95 | 96 | # 计算以1899年12月31日(星期日)为基准日开始的第m个朔日, 即初一 OUT:阳历 97 | # M = 1.6 + 29.5306 * m + 0.4 * sin(1 - 0.45058 * m) 误差在0.2天左右 98 | def getShuori1900(m=1): 99 | try: 100 | m = int(m) 101 | except: 102 | return None 103 | startDT = datetime.datetime(1899,12,31) 104 | days = 1.6 + 29.5306*m +0.4*math.sin(1-0.45058*m) 105 | delta = datetime.timedelta(days=days) 106 | return startDT+delta 107 | 108 | 109 | 110 | 111 | # 设定基准起位 112 | TIAN_GAN = u"甲,乙,丙,丁,戊,己,庚,辛,壬,癸".split(",") 113 | DI_ZHI = u"子,丑,寅,卯,辰,巳,午,未,申,酉,戌,亥".split(",") 114 | SHU_XIANG = u"猪,鼠,牛,虎,兔,龙,蛇,马,羊,猴,鸡,狗".split(",") 115 | JIA_ZHI60 = { 116 | 1:u"甲子", 2:u"乙丑", 3:u"丙寅", 4:u"丁卯", 5:u"戊辰", 6:u"己巳", 7:u"庚午", 8:u"辛未", 9:u"壬申", 10:u"癸酉", 117 | 11:u"甲戌", 12:u"乙亥", 13:u"丙子", 14:u"丁丑", 15:u"戊寅", 16:u"己卯", 17:u"庚辰", 18:u"辛巳", 19:u"壬午", 20:u"癸未", 118 | 21:u"甲申", 22:u"乙酉", 23:u"丙戌", 24:u"丁亥",25:u"戊子", 26:u"己丑", 27:u"庚寅", 28:u"辛卯", 29:u"壬辰", 30:u"癸巳", 119 | 31:u"甲午", 32:u"乙未", 33:u"丙申", 34:u"丁酉", 35:u"戊戌", 36:u"己亥", 37:u"庚子", 38:u"辛丑", 39:u"壬寅", 40:u"癸卯", 120 | 41:u"甲辰", 42:u"乙巳", 43:u"丙午", 44:u"丁未", 45:u"戊申", 46:u"己酉", 47:u"庚戌", 48:u"辛亥",49:u"壬子", 50:u"癸丑", 121 | 51:u"甲寅", 52:u"乙卯", 53:u"丙辰", 54:u"丁巳", 55:u"戊午", 56:u"己未",57:u"庚申", 58:u"辛酉", 59:u"壬戌", 60:u"癸亥" 122 | } 123 | 124 | # 从0-23小时 对应的地支, 是固定的 23:00-0:59 子, 1:00-2:59 丑 125 | def getHourZhi(n,num=False): 126 | try: 127 | n=int(n) 128 | cnt = (n+1)/2 129 | if cnt==12: 130 | cnt = 0 131 | if num: 132 | return cnt+1 # 从1开始 133 | return DI_ZHI[cnt] 134 | except: 135 | return "" 136 | 137 | 138 | # 时干支 IN:datetime type ,OUT:干支 139 | def getHourGanzhi(dt,num=False): 140 | #以1901年1月1日凌晨一点为基准点 此刻是乙丑时的开始 141 | startDT=datetime.datetime(year=1901, month=1, day=1, hour=1) 142 | #60干支乙丑是第二个,以0为起点,则编号为1 143 | startGanzhi=1 144 | if not isinstance(dt, datetime.datetime): 145 | return "" 146 | #计算离基准时刻过去了多少时间 147 | delta = dt - startDT 148 | if delta.seconds<0: 149 | return "" 150 | #计算时刻的干支编号 151 | hours = delta.days*24 + delta.seconds/3600 152 | ganNum = (startGanzhi + hours/2)%10 153 | if num: # 返回数字形式 154 | return (ganNum+1,getHourZhi(dt.hour,num=True)) 155 | return (TIAN_GAN[ganNum] , getHourZhi(dt.hour)) 156 | 157 | 158 | 159 | 160 | # 日干支 IN:datetime type ,OUT:干支 161 | def getDayGanzhi(dt,num=False): 162 | #函数返回60干支编号,编号范围[1,60],1901年1月1日为基准点,当天是乙卯日。 163 | if not isinstance(dt, datetime.date): 164 | return "" 165 | startdate=datetime.datetime(1901,1,1) 166 | startganzhi=16 167 | delta = dt - startdate 168 | if delta.days + delta.seconds<0: 169 | return "" 170 | res=(startganzhi+delta.days)%60 171 | if res == 0: 172 | res=60 173 | ganNum = (res-1)%10 174 | zhiNum = (res-1)%12 175 | if num: 176 | return (ganNum+1,zhiNum+1) 177 | return (TIAN_GAN[ganNum],DI_ZHI[zhiNum]) 178 | 179 | 180 | # 年干支 ,以每年立春时刻变换年干支. 181 | # 立春都在阳历的2月 4或5号 182 | def getYearGanzhi(dt,num=False): 183 | if not isinstance(dt,datetime.datetime): 184 | return "" 185 | if dt.year < 1900: 186 | return "" 187 | # 当年立春日期 188 | springDt = getJieqi(dt.year,x=3) 189 | # 比立春更早的是上一年的干支. 190 | y = dt.year 191 | if dt < springDt: 192 | y -= 1 193 | ganNum = (y-4)%10 194 | zhiNum = (y-4)%12 195 | if num: 196 | return (ganNum+1,zhiNum+1) 197 | return (TIAN_GAN[ganNum],DI_ZHI[zhiNum]) 198 | 199 | 200 | 201 | # 月干支 根据24节气时刻计算的,也就是每隔两个节气是一个月。不过以月初一为界的情况下认为闰月是不更换月干支的。 202 | def getMonthGanzhi(dt,num=False): 203 | # 月支 按阴历正月(立春当天开始)为寅(2),二月为卯(3)...十二月为丑(1),对应气节. 204 | # 推算月干 = 年干x2+月支 超过10则减去10的倍数到0-9,0视做10 205 | # 阴历月份数字 11 12 1 2 3 4 5 6 7 8 9 10 206 | # 子,丑,寅,卯,辰,巳,午,未,申,酉,戌,亥 207 | # 对应地支索引 0 1 2 3 4 5 6 7 8 9 10 11 208 | # 月干列表: 209 | # 年 份 一月 二月 三月 四月 五月 六月 七月 八月 九月 十月 十一月 十二月 210 | # 甲、己 丙寅 丁卯 戊辰 己巳 庚午 辛未 壬申 癸酉 甲戌 乙亥 丙子 丁丑 211 | # 乙、庚 戊寅 己卯 庚辰 辛巳 壬午 癸未 甲申 乙酉 丙戌 丁亥 戊子 己丑 212 | # 丙、辛 庚寅 辛卯 壬辰 癸巳 甲午 乙未 丙申 丁酉 戊戌 己亥 庚子 辛丑 213 | # 丁、壬 壬寅 癸卯 甲辰 乙巳 丙午 丁未 戊申 己酉 庚戌 辛亥 壬子 癸丑 214 | # 戊、癸 甲寅 乙卯 丙辰 丁巳 戊午 己未 庚申 辛酉 壬戌 癸亥 甲子 乙丑 215 | if not isinstance(dt,datetime.datetime): 216 | return "" 217 | if dt.year < 1900: 218 | return "" 219 | # 月支变改日期表. 如 (5, 4, 6, 5, 5, 6, 7, 7, 8, 8, 7, 7) 220 | # 对应地支 丑(小寒) 寅(立春) 卯 辰 巳 午 未 申 酉 戌 亥 子 221 | # 取得当年节气变更列表,只有节那部分. 222 | jieqiDtList = getJieqiList_byYear(dt.year,jie_only=True) 223 | # 索引最开始对应 丑 1 224 | startzhi = 1 225 | zhiNum = 0 # 从小寒日期之前开始, 为子,索引0 226 | for jieqiDT,index in zip(jieqiDtList,range(12)): 227 | if dt >= jieqiDT: 228 | zhiNum = startzhi + index 229 | ganList = {2:1, 3:2, 4:3, 5:4, 6:5, 7:6, 8:7, 9:8, 10:9, 11:10, 0:11,1:12} 230 | yg = getYearGanzhi(dt,num=True)[0] 231 | ganNum = (yg*2 +ganList[zhiNum])%10 232 | if ganNum == 0: 233 | ganNum = 10 234 | ganNum -= 1 235 | if num: 236 | return (ganNum+1,zhiNum+1) 237 | return (TIAN_GAN[ganNum],DI_ZHI[zhiNum]) 238 | 239 | 240 | 241 | 242 | 243 | # 属相 需要看立春前后. 244 | def getShuxiang(dt): 245 | # >>> birthDate2shuXiang(1983,1,1) >>> 狗 246 | # >>> birthDate2shuXiang(1983,4,1) >>> 猪 247 | if not isinstance(dt,datetime.datetime): 248 | return "" 249 | if dt.year < 1900: 250 | return "" 251 | index = (dt.year+8)%12 252 | # 当年立春日期 253 | sprintDT = getJieqi(dt.year,x=3) 254 | if dt >= sprintDT: 255 | index = (index + 1)%12 256 | return SHU_XIANG[index] 257 | 258 | # 天干地支某项转化为五行 259 | def ganzhi2Wuxing(gz): 260 | A = u"子,亥,寅,卯,巳,午,申,酉,辰,戌,丑,未,甲,乙,丙,丁,戊,己,庚,辛,壬,癸".split(",") 261 | B = u"水,水,木,木,火,火,金,金,土,土,土,土,木,木,火,火,火,火,金,金,水,水".split(',') 262 | if gz in A: 263 | return B[A.index(gz)] 264 | return "" 265 | 266 | 267 | # 天干地支一组转化为纳音 268 | def ganzhi2Nayin(gz): 269 | nayinDict = { 270 | u"甲子,乙丑":u"海中金", u"丙寅,丁卯":u"炉中火", u"戊辰,己巳":u"大林木", 271 | u"庚午,辛未":u"路旁土", u"壬申,癸酉":u"剑锋金", u"甲戌,乙亥":u"山头火", 272 | u"丙子,丁丑":u"漳下水", u"戊寅,己卯":u"城头土", u"庚辰,辛巳":u"白腊金", 273 | u"壬午,癸未":u"杨柳木", u"甲申,乙酉":u"泉中水", u"丙戌,丁亥":u"屋上土", 274 | u"戊子,己丑":u"霹雳火", u"庚寅,辛卯":u"松柏木", u"壬辰,癸巳":u"长流水", 275 | u"甲午,乙未":u"砂石金", u"丙申,丁酉":u"山下火", u"戊戌,己亥":u"平地木", 276 | u"庚子,辛丑":u"壁上土", u"壬寅,癸卯":u"金薄金", u"甲辰,乙巳":u"覆灯火", 277 | u"丙午,丁未":u"天河水", u"戊申,己酉":u"大驿土", u"庚戌,辛亥":u"钗环金", 278 | u"壬子,癸丑":u"桑柘木", u"甲寅,乙卯":u"大溪水", u"丙辰,丁巳":u"沙中土", 279 | u"戊午,己未":u"天上火", u"庚申,辛酉":u"石榴木", u"壬戌,癸亥":u"大海水" 280 | } 281 | for key,val in nayinDict.iteritems(): 282 | if gz in key: 283 | return val 284 | return "" 285 | 286 | 287 | 288 | 289 | 290 | 291 | # 阴历月 IN:月份数字 292 | def getLunarMonth_cn(n,postfix=True): 293 | monthList = u"正,二,三,四,五,六,七,八,九,十,十一,腊".split(",") 294 | res = "" 295 | try: 296 | n = int(n) 297 | res = monthList[(n-1)] 298 | except:pass 299 | if postfix: 300 | return res+u"月" 301 | return res 302 | 303 | def getNum2cn(n): 304 | try: 305 | n = int(n) 306 | except: 307 | return None 308 | if n>9 or n < 0: 309 | return None 310 | str = u'零,壹,貳,叁,肆,伍,陆,染,捌,玖'.split(",") 311 | return str[n] 312 | 313 | 314 | # 阴历日 IN: 天数字 315 | def getLunarDay_cn(n): 316 | dayList = u'初一,初二,初三,初四,初五,初六,初七,初八,初九,初十,十一,十二,十三,十四,十五,十六,十七,' \ 317 | u'十八,十九,二十,廿一,廿二,廿三,廿四,廿五,廿六,廿七,廿八,廿九,三十'.split(",") 318 | try: 319 | n = int(n) 320 | return dayList[n-1] 321 | except:pass 322 | return "" 323 | 324 | 325 | # 起大运岁计算 OUT:dt-type 326 | def getQiyun_Date(dt,sex=1): 327 | # 默认sex=1 为男 sex=0为女 328 | if not isinstance(dt,datetime.datetime): 329 | return "" 330 | # 出生年干. 起位 甲乙丙丁.... 1开始 331 | yg = getYearGanzhi(dt,num=True)[0] 332 | # 年干是[甲,丙,戊,庚,壬], yg%2==1 ,是阳年, 男顺向, 女逆向 333 | # 年干是[乙,丁,己,辛,癸], yg%2==0, 是阴年, 男逆向, 女顺向 334 | direction = 1 # 方向 1顺 0逆 335 | if yg%2==1: # 阳年 336 | if not sex: 337 | direction=0 338 | else: # 阴年 339 | if sex: 340 | direction=0 341 | 342 | # 求 出生的下一个月立节日期, 与上一个月立节日期 343 | if dt.month == 12: 344 | jieqiNextMonthDt = getJieqiList_byMonth(dt.year+1,1,jie_only=True)[0] 345 | else: 346 | jieqiNextMonthDt = getJieqiList_byMonth(dt.year,dt.month+1,jie_only=True)[0] 347 | if dt.month == 1: 348 | jieqiPreMonthDt = getJieqiList_byMonth(dt.year-1,12,jie_only=True)[0] 349 | else: 350 | jieqiPreMonthDt = getJieqiList_byMonth(dt.year,dt.month-1,jie_only=True)[0] 351 | # 出生上一个立节日期, 与上一个月的立节日期,可能相同,可能不同. 352 | jieqiList = getJieqiList_byMonth(dt.year-1,12,jie_only=True) + getJieqiList_byYear(dt.year,jie_only=True) 353 | jieqiPreDt = None 354 | i = len(jieqiList) -1 355 | while dt <= jieqiList[i]: 356 | i -= 1 357 | jieqiPreDt = jieqiList[i] 358 | if dt in jieqiList: # 刚好出生在节气时刻, 虽然可能性很小 359 | jieqiPreDt = dt 360 | 361 | if direction: # 顺向计算 阳男,阴女 362 | # 出生至下一日起,到下月立节的日,时 为止,三日折1年,一日折4月,一时辰折10天 363 | deltaNextMonth = jieqiNextMonthDt - dt 364 | deltaPre = dt - jieqiPreDt # 求出生距上一个立节的天数 365 | delta_days = deltaNextMonth.days 366 | delta_hours = deltaNextMonth.seconds/3600 + deltaPre.days + deltaPre.seconds/3600 # 补上出生日距前一个立节的天数 367 | # 折算年,月,日 指出生后的第几年几月 那个月的立节后第几日 368 | daYun_years = delta_days/3 369 | daYun_months = (delta_days%3) * 4 370 | daYun_days = (delta_hours/2)*10 371 | 372 | else: # 逆向, 阴男,阳女 373 | # 出生日的上一日起,到上月立节的日,时 为止,三日折1年,一日折4月,一时辰折10天 374 | deltaPreMonth = dt - jieqiPreMonthDt 375 | deltaPre = dt - jieqiPreDt 376 | delta_days = deltaPreMonth.days 377 | delta_hours = deltaPreMonth.seconds/3600 + deltaPre.days + deltaPre.seconds/3600 # 补上出生日到下一个立节的天数 378 | # 折算年,月,日 指出生后的第几年几月 那个月的立节后第几日 379 | daYun_years = delta_days/3 380 | daYun_months = (delta_days%3) * 4 381 | daYun_days = (delta_hours/2)*10 382 | 383 | # 返回实际起运日期 384 | final_y = dt.year + daYun_years 385 | final_m = dt.month + daYun_months 386 | while final_m > 12: 387 | final_m -= 12 388 | final_y += 1 389 | # 取得出生后 第几年几月的那个月的立节 390 | final_jieqiDt = getJieqiList_byMonth(final_y,final_m,jie_only=True)[0] 391 | final_DT = final_jieqiDt + datetime.timedelta(days=daYun_days) 392 | return final_DT 393 | 394 | 395 | 396 | # 排小运 按虚岁算, 有一年算一年, 阳男阴女顺行, 阴男阳女逆行 397 | # 由时柱排起 按60甲子顺序下去, 如1998戊寅年五月初六壬子时生男, 一岁小运是癸丑, 二岁是甲寅 如果生女,则逆顺 一岁是辛亥,二岁庚戌. 398 | # OUT: [1岁开始对应的60甲子干支,...] 399 | def getXiaoyun_list(dt,sex=1,ages=1): 400 | # 默认返回 1岁对应的60甲子 401 | # 默认sex=1 为男 sex=0为女 402 | if not isinstance(dt,datetime.datetime): 403 | return None 404 | try: 405 | ages = abs(int(ages)) 406 | except: 407 | return None 408 | # 出生年干. 起位 甲乙丙丁.... 1开始 409 | yg = getYearGanzhi(dt,num=True)[0] 410 | # 年干是[甲,丙,戊,庚,壬], yg%2==1 ,是阳年, 男顺向, 女逆向 411 | # 年干是[乙,丁,己,辛,癸], yg%2==0, 是阴年, 男逆向, 女顺向 412 | direction = 1 # 方向 1顺 0逆 413 | tgz = "".join(getHourGanzhi(dt)) 414 | cnt = JIA_ZHI60.values().index(tgz) +1 # 出生时干支对应60甲子的序号, 作为0岁起位, 415 | res = [] 416 | if (yg%2==1 and sex) or (yg%2==0 and not sex): # 顺向 417 | for i in range(1,ages+1): 418 | cnt += 1 419 | if cnt>60: # 指针大于60,复位1 420 | cnt=1 421 | res.append(JIA_ZHI60[cnt]) 422 | else: #逆向 423 | for i in range(1,ages+1): 424 | cnt -= 1 425 | if cnt < 1: # 指针小于1,复位60 426 | cnt=60 427 | res.append(JIA_ZHI60[cnt]) 428 | return res 429 | 430 | 431 | 432 | # 旬空 IN: 60甲子日对应的 天干,地支的数字 OUT:两个 地支 433 | def getXunkong(ganNum,zhiNum,num=False): 434 | """ 435 | 空亡的计算方法:11-天干数+地支数。计算的结果所对应的地支数即为空亡。如果计算结果>12 减去12就是空亡。 436 | 如甲子日空亡为11-1+1=11,11为戌,即为戌亥空。 437 | """ 438 | try: 439 | ganNum = int(ganNum) 440 | zhiNum = int(zhiNum) 441 | except: 442 | return "" 443 | cnt = 11-ganNum+zhiNum 444 | if cnt>12: 445 | cnt -= 12 446 | # cnt 空亡 地支序号. 447 | cnt2 = cnt+1 448 | if cnt2 > 12: 449 | cnt2 = 1 450 | if num: 451 | return (cnt,cnt2) 452 | return (DI_ZHI[cnt-1],DI_ZHI[cnt2-1]) 453 | 454 | 455 | 456 | # 四住推命 457 | #  458 | 459 | 460 | 461 | 462 | 463 | # 真太阳时间换算, IN:平太阳时间 dt类型 464 | def getTrueSunDatetime(dt=None): 465 | if not isinstance(dt,datetime.datetime): 466 | return "" 467 | try: 468 | dateStr = dt.strftime('%m-%d') 469 | except: 470 | return "" 471 | dateList = { 472 | "01-01":datetime.timedelta(minutes=-3,seconds=-9), "01-02":datetime.timedelta(minutes=-3,seconds=-38), 473 | "01-03":datetime.timedelta(minutes=-4,seconds=-6), "01-04":datetime.timedelta(minutes=-4,seconds=-33), 474 | "01-05":datetime.timedelta(minutes=-5,seconds=-1), "01-06":datetime.timedelta(minutes=-5,seconds=-27), 475 | "01-07":datetime.timedelta(minutes=-5,seconds=-54), "01-08":datetime.timedelta(minutes=-6,seconds=-20), 476 | "01-09":datetime.timedelta(minutes=-6,seconds=-45), "01-10":datetime.timedelta(minutes=-7,seconds=-10), 477 | "01-11":datetime.timedelta(minutes=-7,seconds=-35), "01-12":datetime.timedelta(minutes=-7,seconds=-59), 478 | "01-13":datetime.timedelta(minutes=-8,seconds=-22), "01-14":datetime.timedelta(minutes=-8,seconds=-45), 479 | "01-15":datetime.timedelta(minutes=-9,seconds=-7), "01-16":datetime.timedelta(minutes=-9,seconds=-28), 480 | "01-17":datetime.timedelta(minutes=-9,seconds=-49), "01-18":datetime.timedelta(minutes=-10,seconds=-9), 481 | "01-19":datetime.timedelta(minutes=-10,seconds=-28), "01-20":datetime.timedelta(minutes=-10,seconds=-47), 482 | "01-21":datetime.timedelta(minutes=-11,seconds=-5), "01-22":datetime.timedelta(minutes=-11,seconds=-22), 483 | "01-23":datetime.timedelta(minutes=-11,seconds=-38), "01-24":datetime.timedelta(minutes=-11,seconds=-54), 484 | "01-25":datetime.timedelta(minutes=-12,seconds=-8), "01-26":datetime.timedelta(minutes=-12,seconds=-22), 485 | "01-27":datetime.timedelta(minutes=-12,seconds=-35), "01-28":datetime.timedelta(minutes=-12,seconds=-59), 486 | "01-29":datetime.timedelta(minutes=-13,seconds=-10), "01-30":datetime.timedelta(minutes=-13,seconds=-19), 487 | "01-31":datetime.timedelta(minutes=-13,seconds=-37), "02-01":datetime.timedelta(minutes=-13,seconds=-44), 488 | "02-02":datetime.timedelta(minutes=-13,seconds=-50), "02-03":datetime.timedelta(minutes=-13,seconds=-56), 489 | "02-04":datetime.timedelta(minutes=-14,seconds=-1), "02-05":datetime.timedelta(minutes=-14,seconds=-5), 490 | "02-06":datetime.timedelta(minutes=-14,seconds=-9), "02-07":datetime.timedelta(minutes=-14,seconds=-11), 491 | "02-08":datetime.timedelta(minutes=-14,seconds=-13), "02-09":datetime.timedelta(minutes=-14,seconds=-14), 492 | "02-10":datetime.timedelta(minutes=-14,seconds=-15), "02-11":datetime.timedelta(minutes=-14,seconds=-14), 493 | "02-12":datetime.timedelta(minutes=-14,seconds=-13), "02-13":datetime.timedelta(minutes=-14,seconds=-11), 494 | "02-14":datetime.timedelta(minutes=-14,seconds=-8), "02-15":datetime.timedelta(minutes=-14,seconds=-5), 495 | "02-16":datetime.timedelta(minutes=-14,seconds=-1), "02-17":datetime.timedelta(minutes=-13,seconds=-56), 496 | "02-18":datetime.timedelta(minutes=-13,seconds=-51), "02-19":datetime.timedelta(minutes=-13,seconds=-44), 497 | "02-20":datetime.timedelta(minutes=-13,seconds=-38), "02-21":datetime.timedelta(minutes=-13,seconds=-30), 498 | "02-22":datetime.timedelta(minutes=-13,seconds=-22), "02-23":datetime.timedelta(minutes=-13,seconds=-13), 499 | "02-24":datetime.timedelta(minutes=-11,seconds=-4), "02-25":datetime.timedelta(minutes=-12,seconds=-54), 500 | "02-26":datetime.timedelta(minutes=-12,seconds=-43), "02-27":datetime.timedelta(minutes=-12,seconds=-32), 501 | "02-28":datetime.timedelta(minutes=-12,seconds=-21), "02-29":datetime.timedelta(minutes=-12,seconds=-8), 502 | "03-01":datetime.timedelta(minutes=-11,seconds=-56), "03-02":datetime.timedelta(minutes=-11,seconds=-43), 503 | "03-03":datetime.timedelta(minutes=-11,seconds=-29), "03-04":datetime.timedelta(minutes=-11,seconds=-15), 504 | "03-05":datetime.timedelta(minutes=-11,seconds=-1), "03-06":datetime.timedelta(minutes=-10,seconds=-47), 505 | "03-07":datetime.timedelta(minutes=-10,seconds=-32), "03-08":datetime.timedelta(minutes=-10,seconds=-16), 506 | "03-09":datetime.timedelta(minutes=-10,seconds=-1), "03-10":datetime.timedelta(minutes=-9,seconds=-45), 507 | "03-11":datetime.timedelta(minutes=-9,seconds=-28), "03-12":datetime.timedelta(minutes=-9,seconds=-12), 508 | "03-13":datetime.timedelta(minutes=-8,seconds=-55), "03-14":datetime.timedelta(minutes=-8,seconds=-38), 509 | "03-15":datetime.timedelta(minutes=-8,seconds=-21), "03-16":datetime.timedelta(minutes=-8,seconds=-4), 510 | "03-17":datetime.timedelta(minutes=-7,seconds=-46), "03-18":datetime.timedelta(minutes=-7,seconds=-29), 511 | "03-19":datetime.timedelta(minutes=-7,seconds=-11), "03-20":datetime.timedelta(minutes=-6,seconds=-53), 512 | "03-21":datetime.timedelta(minutes=-6,seconds=-35), "03-22":datetime.timedelta(minutes=-6,seconds=-17), 513 | "03-23":datetime.timedelta(minutes=-5,seconds=-58), "03-24":datetime.timedelta(minutes=-5,seconds=-40), 514 | "03-25":datetime.timedelta(minutes=-5,seconds=-22), "03-26":datetime.timedelta(minutes=-5,seconds=-4), 515 | "03-27":datetime.timedelta(minutes=-4,seconds=-45), "03-28":datetime.timedelta(minutes=-4,seconds=-27), 516 | "03-29":datetime.timedelta(minutes=-4,seconds=-9), "03-30":datetime.timedelta(minutes=-3,seconds=-51), 517 | "03-31":datetime.timedelta(minutes=-3,seconds=-33), "04-01":datetime.timedelta(minutes=-3,seconds=-16), 518 | "04-02":datetime.timedelta(minutes=-2,seconds=-58), "04-03":datetime.timedelta(minutes=-2,seconds=-41), 519 | "04-04":datetime.timedelta(minutes=-2,seconds=-24), "04-05":datetime.timedelta(minutes=-2,seconds=-7), 520 | "04-06":datetime.timedelta(minutes=-1,seconds=-50), "04-07":datetime.timedelta(minutes=-1,seconds=-33), 521 | "04-08":datetime.timedelta(minutes=-1,seconds=-17), "04-09":datetime.timedelta(minutes=-1,seconds=-1), 522 | "04-10":datetime.timedelta(minutes=+0,seconds=+46), "04-11":datetime.timedelta(minutes=+0,seconds=+30), 523 | "04-12":datetime.timedelta(minutes=+0,seconds=+16), "04-13":datetime.timedelta(minutes=+0,seconds=+1), 524 | "04-14":datetime.timedelta(minutes=+0,seconds=+13), "04-15":datetime.timedelta(minutes=+0,seconds=+27), 525 | "04-16":datetime.timedelta(minutes=+0,seconds=+41), "04-17":datetime.timedelta(minutes=+0,seconds=+54), 526 | "04-18":datetime.timedelta(minutes=+1,seconds=+6), "04-19":datetime.timedelta(minutes=+1,seconds=+19), 527 | "04-20":datetime.timedelta(minutes=+1,seconds=+31), "04-21":datetime.timedelta(minutes=+1,seconds=+42), 528 | "04-22":datetime.timedelta(minutes=+1,seconds=+53), "04-23":datetime.timedelta(minutes=+2,seconds=+4), 529 | "04-24":datetime.timedelta(minutes=+2,seconds=+14), "04-25":datetime.timedelta(minutes=+2,seconds=+23), 530 | "04-26":datetime.timedelta(minutes=+2,seconds=+33), "04-27":datetime.timedelta(minutes=+2,seconds=+41), 531 | "04-28":datetime.timedelta(minutes=+2,seconds=+49), "04-29":datetime.timedelta(minutes=+2,seconds=+57), 532 | "04-30":datetime.timedelta(minutes=+3,seconds=+4), "05-01":datetime.timedelta(minutes=+1,seconds=+10), 533 | "05-02":datetime.timedelta(minutes=+3,seconds=+16), "05-03":datetime.timedelta(minutes=+3,seconds=+21), 534 | "05-04":datetime.timedelta(minutes=+3,seconds=+26), "05-05":datetime.timedelta(minutes=+3,seconds=+30), 535 | "05-06":datetime.timedelta(minutes=+3,seconds=+37), "05-07":datetime.timedelta(minutes=+3,seconds=+36), 536 | "05-08":datetime.timedelta(minutes=+3,seconds=+39), "05-09":datetime.timedelta(minutes=+3,seconds=+40), 537 | "05-10":datetime.timedelta(minutes=+3,seconds=+42), "05-11":datetime.timedelta(minutes=+3,seconds=+42), 538 | "05-12":datetime.timedelta(minutes=+3,seconds=+42), "05-13":datetime.timedelta(minutes=+3,seconds=+42), 539 | "05-14":datetime.timedelta(minutes=+3,seconds=+41), "05-15":datetime.timedelta(minutes=+3,seconds=+39), 540 | "05-16":datetime.timedelta(minutes=+3,seconds=+37), "05-17":datetime.timedelta(minutes=+3,seconds=+34), 541 | "05-18":datetime.timedelta(minutes=+3,seconds=+31), "05-19":datetime.timedelta(minutes=+3,seconds=+27), 542 | "05-20":datetime.timedelta(minutes=+3,seconds=+23), "05-21":datetime.timedelta(minutes=+3,seconds=+18), 543 | "05-22":datetime.timedelta(minutes=+3,seconds=+13), "05-23":datetime.timedelta(minutes=+3,seconds=+7), 544 | "05-24":datetime.timedelta(minutes=+3,seconds=+1), "05-25":datetime.timedelta(minutes=+2,seconds=+54), 545 | "05-26":datetime.timedelta(minutes=+2,seconds=+47), "05-27":datetime.timedelta(minutes=+2,seconds=+39), 546 | "05-28":datetime.timedelta(minutes=+2,seconds=+31), "05-29":datetime.timedelta(minutes=+2,seconds=+22), 547 | "05-30":datetime.timedelta(minutes=+2,seconds=+13), "05-31":datetime.timedelta(minutes=+2,seconds=+4), 548 | "06-01":datetime.timedelta(minutes=+1,seconds=+54), "06-02":datetime.timedelta(minutes=+1,seconds=+44), 549 | "06-03":datetime.timedelta(minutes=+1,seconds=+34), "06-04":datetime.timedelta(minutes=+1,seconds=+23), 550 | "06-05":datetime.timedelta(minutes=+1,seconds=+12), "06-06":datetime.timedelta(minutes=+1,seconds=+0), 551 | "06-07":datetime.timedelta(minutes=+0,seconds=+48), "06-08":datetime.timedelta(minutes=+0,seconds=+36), 552 | "06-09":datetime.timedelta(minutes=+0,seconds=+24), "06-10":datetime.timedelta(minutes=+0,seconds=+12), 553 | "06-11":datetime.timedelta(minutes=+0,seconds=+1), "06-12":datetime.timedelta(minutes=+0,seconds=+14), 554 | "06-13":datetime.timedelta(minutes=+0,seconds=+39), "06-14":datetime.timedelta(minutes=+0,seconds=+52), 555 | "06-15":datetime.timedelta(minutes=-1,seconds=-5), "06-16":datetime.timedelta(minutes=-1,seconds=-18), 556 | "06-17":datetime.timedelta(minutes=-1,seconds=-31), "06-18":datetime.timedelta(minutes=-1,seconds=-45), 557 | "06-19":datetime.timedelta(minutes=-1,seconds=-57), "06-20":datetime.timedelta(minutes=-2,seconds=-10), 558 | "06-21":datetime.timedelta(minutes=-2,seconds=-23), "06-22":datetime.timedelta(minutes=-2,seconds=-36), 559 | "06-23":datetime.timedelta(minutes=-2,seconds=-48), "06-24":datetime.timedelta(minutes=-3,seconds=-1), 560 | "06-25":datetime.timedelta(minutes=-3,seconds=-13), "06-26":datetime.timedelta(minutes=-3,seconds=-25), 561 | "06-27":datetime.timedelta(minutes=-3,seconds=-37), "06-28":datetime.timedelta(minutes=-3,seconds=-49), 562 | "06-29":datetime.timedelta(minutes=-4,seconds=-0), "06-30":datetime.timedelta(minutes=-4,seconds=-11), 563 | "07-01":datetime.timedelta(minutes=-4,seconds=-22), "07-02":datetime.timedelta(minutes=-4,seconds=-33), 564 | "07-03":datetime.timedelta(minutes=-4,seconds=-43), "07-04":datetime.timedelta(minutes=-4,seconds=-53), 565 | "07-05":datetime.timedelta(minutes=-5,seconds=-2), "07-06":datetime.timedelta(minutes=-5,seconds=-11), 566 | "07-07":datetime.timedelta(minutes=-5,seconds=-20), "07-08":datetime.timedelta(minutes=-5,seconds=-28), 567 | "07-09":datetime.timedelta(minutes=-5,seconds=-36), "07-10":datetime.timedelta(minutes=-5,seconds=-43), 568 | "07-11":datetime.timedelta(minutes=-5,seconds=-50), "07-12":datetime.timedelta(minutes=-5,seconds=-56), 569 | "07-13":datetime.timedelta(minutes=-6,seconds=-2), "07-14":datetime.timedelta(minutes=-6,seconds=-8), 570 | "07-15":datetime.timedelta(minutes=-6,seconds=-12), "07-16":datetime.timedelta(minutes=-6,seconds=-16), 571 | "07-17":datetime.timedelta(minutes=-6,seconds=-20), "07-18":datetime.timedelta(minutes=-6,seconds=-23), 572 | "07-19":datetime.timedelta(minutes=-6,seconds=-25), "07-20":datetime.timedelta(minutes=-6,seconds=-27), 573 | "07-21":datetime.timedelta(minutes=-6,seconds=-29), "07-22":datetime.timedelta(minutes=-6,seconds=-29), 574 | "07-23":datetime.timedelta(minutes=-6,seconds=-29), "07-24":datetime.timedelta(minutes=-6,seconds=-29), 575 | "07-25":datetime.timedelta(minutes=-6,seconds=-28), "07-26":datetime.timedelta(minutes=-6,seconds=-26), 576 | "07-27":datetime.timedelta(minutes=-6,seconds=-24), "07-28":datetime.timedelta(minutes=-6,seconds=-21), 577 | "07-29":datetime.timedelta(minutes=-6,seconds=-17), "07-30":datetime.timedelta(minutes=-6,seconds=-13), 578 | "07-31":datetime.timedelta(minutes=-6,seconds=-8), "08-01":datetime.timedelta(minutes=-6,seconds=-3), 579 | "08-02":datetime.timedelta(minutes=-5,seconds=-57), "08-03":datetime.timedelta(minutes=-5,seconds=-51), 580 | "08-04":datetime.timedelta(minutes=-5,seconds=-44), "08-05":datetime.timedelta(minutes=-5,seconds=-36), 581 | "08-06":datetime.timedelta(minutes=-5,seconds=-28), "08-07":datetime.timedelta(minutes=-5,seconds=-19), 582 | "08-08":datetime.timedelta(minutes=-5,seconds=-10), "08-09":datetime.timedelta(minutes=-5,seconds=-0), 583 | "08-10":datetime.timedelta(minutes=-4,seconds=-50), "08-11":datetime.timedelta(minutes=-4,seconds=-39), 584 | "08-12":datetime.timedelta(minutes=-4,seconds=-27), "08-13":datetime.timedelta(minutes=-4,seconds=-15), 585 | "08-14":datetime.timedelta(minutes=-4,seconds=-2), "08-15":datetime.timedelta(minutes=-3,seconds=-49), 586 | "08-16":datetime.timedelta(minutes=-3,seconds=-36), "08-17":datetime.timedelta(minutes=-3,seconds=-21), 587 | "08-18":datetime.timedelta(minutes=-3,seconds=-7), "08-19":datetime.timedelta(minutes=-2,seconds=-51), 588 | "08-20":datetime.timedelta(minutes=-2,seconds=-36), "08-21":datetime.timedelta(minutes=-2,seconds=-20), 589 | "08-22":datetime.timedelta(minutes=-2,seconds=-3), "08-23":datetime.timedelta(minutes=-1,seconds=-47), 590 | "08-24":datetime.timedelta(minutes=-1,seconds=-29), "08-25":datetime.timedelta(minutes=-1,seconds=-12), 591 | "08-26":datetime.timedelta(minutes=+0,seconds=+54), "08-27":datetime.timedelta(minutes=+0,seconds=+35), 592 | "08-28":datetime.timedelta(minutes=+0,seconds=+17), "08-29":datetime.timedelta(minutes=+0,seconds=+2), 593 | "08-30":datetime.timedelta(minutes=+0,seconds=+21), "08-31":datetime.timedelta(minutes=+0,seconds=+41), 594 | "09-01":datetime.timedelta(minutes=+1,seconds=+0), "09-02":datetime.timedelta(minutes=+1,seconds=+20), 595 | "09-03":datetime.timedelta(minutes=+1,seconds=+40), "09-04":datetime.timedelta(minutes=+2,seconds=+1), 596 | "09-05":datetime.timedelta(minutes=+2,seconds=+21), "09-06":datetime.timedelta(minutes=+2,seconds=+42), 597 | "09-07":datetime.timedelta(minutes=+3,seconds=+3), "09-08":datetime.timedelta(minutes=+3,seconds=+3), 598 | "09-09":datetime.timedelta(minutes=+3,seconds=+24), "09-10":datetime.timedelta(minutes=+3,seconds=+45), 599 | "09-11":datetime.timedelta(minutes=+4,seconds=+6), "09-12":datetime.timedelta(minutes=+4,seconds=+27), 600 | "09-13":datetime.timedelta(minutes=+4,seconds=+48), "09-14":datetime.timedelta(minutes=+5,seconds=+10), 601 | "09-15":datetime.timedelta(minutes=+5,seconds=+31), "09-16":datetime.timedelta(minutes=+5,seconds=+53), 602 | "09-17":datetime.timedelta(minutes=+6,seconds=+14), "09-18":datetime.timedelta(minutes=+6,seconds=+35), 603 | "09-19":datetime.timedelta(minutes=+6,seconds=+57), "09-20":datetime.timedelta(minutes=+7,seconds=+18), 604 | "09-21":datetime.timedelta(minutes=+7,seconds=+39), "09-22":datetime.timedelta(minutes=+8,seconds=+0), 605 | "09-23":datetime.timedelta(minutes=+8,seconds=+21), "09-24":datetime.timedelta(minutes=+8,seconds=+42), 606 | "09-25":datetime.timedelta(minutes=+9,seconds=+2), "09-26":datetime.timedelta(minutes=+9,seconds=+22), 607 | "09-27":datetime.timedelta(minutes=+9,seconds=+42), "09-28":datetime.timedelta(minutes=+10,seconds=+2), 608 | "09-29":datetime.timedelta(minutes=+10,seconds=+21), "09-30":datetime.timedelta(minutes=+10,seconds=+40), 609 | "10-01":datetime.timedelta(minutes=+10,seconds=+59), "10-02":datetime.timedelta(minutes=+11,seconds=+18), 610 | "10-03":datetime.timedelta(minutes=+11,seconds=+36), "10-04":datetime.timedelta(minutes=+11,seconds=+36), 611 | "10-05":datetime.timedelta(minutes=+11,seconds=+53), "10-06":datetime.timedelta(minutes=+12,seconds=+11), 612 | "10-07":datetime.timedelta(minutes=+12,seconds=+28), "10-08":datetime.timedelta(minutes=+12,seconds=+44), 613 | "10-09":datetime.timedelta(minutes=+12,seconds=+60), "10-10":datetime.timedelta(minutes=+13,seconds=+16), 614 | "10-11":datetime.timedelta(minutes=+13,seconds=+16), "10-12":datetime.timedelta(minutes=+13,seconds=+31), 615 | "10-13":datetime.timedelta(minutes=+13,seconds=+45), "10-14":datetime.timedelta(minutes=+13,seconds=+59), 616 | "10-15":datetime.timedelta(minutes=+14,seconds=+13), "10-16":datetime.timedelta(minutes=+14,seconds=+26), 617 | "10-17":datetime.timedelta(minutes=+14,seconds=+38), "10-18":datetime.timedelta(minutes=+14,seconds=+50), 618 | "10-19":datetime.timedelta(minutes=+15,seconds=+1), "10-20":datetime.timedelta(minutes=+15,seconds=+12), 619 | "10-21":datetime.timedelta(minutes=+11,seconds=+21), "10-22":datetime.timedelta(minutes=+15,seconds=+31), 620 | "10-23":datetime.timedelta(minutes=+15,seconds=+40), "10-24":datetime.timedelta(minutes=+15,seconds=+48), 621 | "10-25":datetime.timedelta(minutes=+15,seconds=+55), "10-26":datetime.timedelta(minutes=+16,seconds=+1), 622 | "10-27":datetime.timedelta(minutes=+16,seconds=+7), "10-28":datetime.timedelta(minutes=+16,seconds=+12), 623 | "10-29":datetime.timedelta(minutes=+16,seconds=+16), "10-30":datetime.timedelta(minutes=+16,seconds=+20), 624 | "10-31":datetime.timedelta(minutes=+16,seconds=+22), "11-01":datetime.timedelta(minutes=+16,seconds=+24), 625 | "11-02":datetime.timedelta(minutes=+16,seconds=+25), "11-03":datetime.timedelta(minutes=+16,seconds=+25), 626 | "11-04":datetime.timedelta(minutes=+16,seconds=+24), "11-05":datetime.timedelta(minutes=+16,seconds=+23), 627 | "11-06":datetime.timedelta(minutes=+16,seconds=+21), "11-07":datetime.timedelta(minutes=+16,seconds=+17), 628 | "11-08":datetime.timedelta(minutes=+16,seconds=+13), "11-09":datetime.timedelta(minutes=+16,seconds=+9), 629 | "11-10":datetime.timedelta(minutes=+16,seconds=+3), "11-11":datetime.timedelta(minutes=+15,seconds=+56), 630 | "11-12":datetime.timedelta(minutes=+15,seconds=+49), "11-13":datetime.timedelta(minutes=+15,seconds=+41), 631 | "11-14":datetime.timedelta(minutes=+15,seconds=+32), "11-15":datetime.timedelta(minutes=+15,seconds=+22), 632 | "11-16":datetime.timedelta(minutes=+15,seconds=+11), "11-17":datetime.timedelta(minutes=+14,seconds=+60), 633 | "11-18":datetime.timedelta(minutes=+14,seconds=+47), "11-19":datetime.timedelta(minutes=+14,seconds=+34), 634 | "11-20":datetime.timedelta(minutes=+14,seconds=+20), "11-21":datetime.timedelta(minutes=+14,seconds=+6), 635 | "11-22":datetime.timedelta(minutes=+13,seconds=+50), "11-23":datetime.timedelta(minutes=+13,seconds=+34), 636 | "11-24":datetime.timedelta(minutes=+13,seconds=+17), "11-25":datetime.timedelta(minutes=+12,seconds=+59), 637 | "11-26":datetime.timedelta(minutes=+12,seconds=+40), "11-27":datetime.timedelta(minutes=+12,seconds=+21), 638 | "11-28":datetime.timedelta(minutes=+12,seconds=+1), "11-29":datetime.timedelta(minutes=+11,seconds=+40), 639 | "11-30":datetime.timedelta(minutes=+11,seconds=+18), "12-01":datetime.timedelta(minutes=+10,seconds=+56), 640 | "12-02":datetime.timedelta(minutes=+10,seconds=+33), "12-03":datetime.timedelta(minutes=+10,seconds=+9), 641 | "12-04":datetime.timedelta(minutes=+9,seconds=+45), "12-05":datetime.timedelta(minutes=+9,seconds=+21), 642 | "12-06":datetime.timedelta(minutes=+8,seconds=+55), "12-07":datetime.timedelta(minutes=+8,seconds=+29), 643 | "12-08":datetime.timedelta(minutes=+8,seconds=+3), "12-09":datetime.timedelta(minutes=+7,seconds=+36), 644 | "12-10":datetime.timedelta(minutes=+7,seconds=+9), "12-11":datetime.timedelta(minutes=+6,seconds=+42), 645 | "12-12":datetime.timedelta(minutes=+6,seconds=+14), "12-13":datetime.timedelta(minutes=+5,seconds=+46), 646 | "12-14":datetime.timedelta(minutes=+5,seconds=+17), "12-15":datetime.timedelta(minutes=+4,seconds=+48), 647 | "12-16":datetime.timedelta(minutes=+4,seconds=+19), "12-17":datetime.timedelta(minutes=+3,seconds=+50), 648 | "12-18":datetime.timedelta(minutes=+3,seconds=+21), "12-19":datetime.timedelta(minutes=+2,seconds=+51), 649 | "12-20":datetime.timedelta(minutes=+2,seconds=+22), "12-21":datetime.timedelta(minutes=+1,seconds=+52), 650 | "12-22":datetime.timedelta(minutes=+1,seconds=+22), "12-23":datetime.timedelta(minutes=+0,seconds=+52), 651 | "12-24":datetime.timedelta(minutes=+0,seconds=+23), "12-25":datetime.timedelta(minutes=+0,seconds=+7), 652 | "12-26":datetime.timedelta(minutes=+0,seconds=+37), "12-27":datetime.timedelta(minutes=-1,seconds=-6), 653 | "12-28":datetime.timedelta(minutes=-1,seconds=-36), "12-29":datetime.timedelta(minutes=-2,seconds=-5), 654 | "12-30":datetime.timedelta(minutes=-2,seconds=-34), "12-31":datetime.timedelta(minutes=-3,seconds=-3), 655 | } 656 | return dt+dateList[dateStr] 657 | 658 | 659 | # 最得西方星座 660 | def getConstellation(dt): 661 | """ 662 | 通过cookie.date值,返回星座名,如果都为空,返回今天的星座 663 | """ 664 | if not isinstance(dt,datetime.datetime): 665 | return None 666 | conStr="" 667 | y = dt.year 668 | Fdt = datetime.datetime 669 | if dt>=Fdt(y,1,20) and dt<=Fdt(y,2,18): conStr = u'水瓶座' 670 | elif dt>=Fdt(y,2,19) and dt<=Fdt(y,3,20): conStr = u'双鱼座' 671 | elif dt>=Fdt(y,3,21) and dt<=Fdt(y,4,19): conStr = u'白羊座' 672 | elif dt>=Fdt(y,4,20) and dt<= Fdt(y,5,20): conStr = u'金牛座' 673 | elif dt>=Fdt(y,5,21) and dt<=Fdt(y,6,21): conStr = u'双子座' 674 | elif dt>=Fdt(y,6,22) and dt<=Fdt(y,7,22): conStr = u'巨蟹座' 675 | elif dt>=Fdt(y,7,23) and dt<=Fdt(y,8,22): conStr = u'狮子座' 676 | elif dt>=Fdt(y,8,23) and dt<=Fdt(y,9,22): conStr = u'处女座' 677 | elif dt>=Fdt(y,9,23) and dt<=Fdt(y,10,23): conStr = u'天秤座' 678 | elif dt>=Fdt(y,10,24) and dt<=Fdt(y,11,21): conStr = u'摩羯座' 679 | elif dt>=Fdt(y,11,22) and dt<=Fdt(y,12,21): conStr = u'射手座' 680 | else: 681 | conStr = u'摩竭座' 682 | return conStr 683 | 684 | 685 | class BazhiDate(): 686 | """ 687 | 输入阳历年月日时分,返回天干地支等.# 性别默认为男 , 使用为女: BazhiDate(dt,sex=0) 或 sex=False 688 | """ 689 | def __init__(self,year,month,day,hour=0,minute=0,sex=1): 690 | try: 691 | dt = datetime.datetime(int(year),int(month),int(day),int(hour),int(minute)) 692 | except KeyError: 693 | raise KeyError 694 | if sex: 695 | self.sex = 1 696 | else: 697 | self.sex = 0 698 | self.yg,self.yz = getYearGanzhi(dt) 699 | self.mg,self.mz = getMonthGanzhi(dt) 700 | self.dg,self.dz = getDayGanzhi(dt) 701 | self.tg,self.tz = getHourGanzhi(dt) 702 | self.ygNum,self.yzNum = getYearGanzhi(dt,num=True) 703 | self.mgNum,self.mzNum = getMonthGanzhi(dt,num=True) 704 | self.dgNum,self.dzNum = getDayGanzhi(dt,num=True) 705 | self.tgNum,self.tzNum = getHourGanzhi(dt,num=True) 706 | self.dt = dt 707 | 708 | @property 709 | def trueSunDatetime(self): 710 | """出生真太阳时间""" 711 | return getTrueSunDatetime(self.dt) 712 | 713 | @property 714 | def shuXiang(self): 715 | return getShuxiang(self.dt) 716 | 717 | # 农历日期 718 | def lunarDate_cn(self,sx=False): 719 | lunarDT = lunardate.LunarDate.fromSolarDate(self.dt.year,self.dt.month,self.dt.day) 720 | lunarM = getLunarMonth_cn(lunarDT.month) 721 | lunarD = getLunarDay_cn(lunarDT.day) 722 | lunarY = self.yg+self.yz 723 | if sx: 724 | return lunarY+"("+self.shuXiang+")"+lunarM+lunarD 725 | return lunarY+u"年"+lunarM+lunarD 726 | 727 | 728 | def ganzhiList(self,num=False): 729 | if num: 730 | return (self.ygNum,self.yzNum,self.mgNum,self.mzNum,self.dgNum,self.dzNum,self.tgNum,self.tzNum) 731 | return (self.yg,self.yz,self.mg,self.mz,self.dg,self.dz,self.tg,self.tz) 732 | 733 | 734 | @property 735 | def wuXing(self): 736 | """天干地支转化五行属性 737 | """ 738 | res = {u'金':0, u'木':0, u'水':0, u'火':0, u'土':0} 739 | tgdz = "".join(self.ganzhi) 740 | for i in tgdz: 741 | a = ganzhi2Wuxing(i) 742 | if a in res: 743 | res[a] += 1 744 | return res.items() 745 | 746 | @property 747 | def naYinList(self): 748 | """返回八字纳音""" 749 | res = [] 750 | for gz in [self.yg+self.yz, self.mg+self.mz, self.dg+self.dz, self.tg+self.tz]: 751 | res.append(ganzhi2Nayin(gz)) 752 | return res 753 | 754 | 755 | # 胎元 IN:出生月的天干,地支 unicode, intro:人之生月后紧接着这个月的天干与生日后的第三个月的地支 756 | def taiYuan(self,num=False): 757 | mg=self.mg 758 | mz=self.mz 759 | try: 760 | ganInt = TIAN_GAN.index(mg) 761 | zhiInt = DI_ZHI.index(mz) 762 | ganNewInt = (ganInt+1)%10 763 | zhiNewInt = (zhiInt+3)%12 764 | if num: 765 | return (ganNewInt,zhiNewInt) 766 | return (TIAN_GAN[ganNewInt]+DI_ZHI[zhiNewInt]) 767 | except:pass 768 | return "" 769 | 770 | 771 | # OUT:命宫 天干,地支 IN:年干,月支,时支 intro:把生时落在生月支上,顺数至卯,卯就为命宫。 772 | def mingGong(self,num=False): 773 | TG = u'甲,己,乙,庚,丙,辛,壬,丁,戊,癸'.split(',') # 甲己丙作首,乙庚戊为初,丙辛寻耿起,丁壬壬顺流,戊癸甲上求. 774 | DZ = u'寅,卯,辰,巳,午,未,申,酉,戌,亥,子,丑'.split(",") # 命宫地支 起位 1开始 775 | # DZ = u'*,子,亥,戌,酉,申,未,午,巳,辰,卯,寅,丑'.split(",") # 地支起位以子1,亥2,....丑12 776 | # 以DZ所算的 时支+月支. = 命宫地支 777 | try: 778 | # 求月支,如果已过当月中气(气节序号双数),月支加1 779 | mzInt = DZ.index(self.mz) + 1 # 月支序号 780 | jieqiMiddleDt = getJieqiList_byMonth(self.dt.year,self.dt.month,qi_only=True)[0] 781 | if self.dt >= jieqiMiddleDt: 782 | mzInt += 1 783 | # 时支序号 784 | tzInt = DZ.index(self.tz) + 1 785 | mingGong_zhi_int = (12+mzInt+tzInt - 10)%12 786 | if mingGong_zhi_int == 0: 787 | mingGong_zhi_int == 12 788 | # sumAll = mzInt + tzInt 789 | # if sumAll >=14: 790 | # mingGong_zhi_int = 26 - sumAll 791 | # else: 792 | # mingGong_zhi_int = 14 - sumAll 793 | # 命宫地支序号出来了,不过这个序号是对应DZ 794 | mingGong_zhi = DZ[mingGong_zhi_int-1] 795 | # 求命宫天干 与年上起月法相同. 796 | zhiNum = DI_ZHI.index(mingGong_zhi) + 1 797 | 798 | # 求天干与年上求月法一样.先转为标准起位的序号. 799 | ganList = {2:1, 3:2, 4:3, 5:4, 6:5, 7:6, 8:7, 9:8, 10:9, 11:10, 0:11,1:12} 800 | yg = self.ygNum 801 | ganNum = (yg*2 +ganList[zhiNum])%10 802 | if ganNum == 0: 803 | ganNum = 10 804 | ganNum -= 1 805 | 806 | # yzInt = TG.index(self.yg) 807 | # mingGong_gan_int = (int(yzInt/2)*2+1 + mingGong_zhi_int)%10 808 | # mingGong_gan = TG2[mingGong_gan_int] 809 | # 对应TIAN_GAN ,DI_ZHI的序号 810 | if num: 811 | return (ganNum,zhiNum) 812 | return (TIAN_GAN[ganNum],DI_ZHI[zhiNum]) 813 | except: 814 | return "" 815 | 816 | # 旬空 817 | @property 818 | def xunKong_list(self): 819 | res = [] 820 | for i,j in [(self.ygNum,self.yzNum),(self.mgNum,self.mzNum),(self.dgNum,self.dzNum),(self.tgNum,self.tzNum)]: 821 | res.append("".join(getXunkong(i,j))) 822 | return res 823 | 824 | # 起运日期 需要用到节气数据具体到时辰. 825 | @property 826 | def daYun_date(self): 827 | return getQiyun_Date(self.dt,sex=self.sex) 828 | 829 | # 出年后几年几月起运 大约数 830 | @property 831 | def daYunAfterBirth(self): 832 | newDt = self.daYun_date 833 | deltaY = newDt.year - self.dt.year 834 | deltaM = newDt.month - self.dt.month 835 | if deltaM < 0: 836 | deltaM += 12 837 | deltaY -= 1 838 | return (deltaY,deltaM) 839 | 840 | 841 | 842 | # OUT:小运列表 843 | def xiaoYun_list(self,ages=1): 844 | return getXiaoyun_list(self.dt,sex=self.sex,ages=ages) 845 | 846 | # 星座 847 | @property 848 | def constellation(self): 849 | return getConstellation(self.dt) 850 | 851 | 852 | 853 | 854 | 855 | 856 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | lunar 2 | ===== 3 | 4 | # 热词:阴历,天干,地支,五行,算命 5 | 6 | import lunar 7 | imprt datetime 8 | 9 | myBZ = lunar.BazhiDate(1999,1,1) 10 | 11 | print u"天干地支", myBZ.ganzhi() 12 | 13 | print u"纳音",myBZ.nayin 14 | 15 | print u"属相",myBZ.shuXiang 16 | 17 | ... 18 | -------------------------------------------------------------------------------- /read.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kiddx01/lunar/cb9110759afc6fe099c56fce140e334dee6ee2cf/read.txt --------------------------------------------------------------------------------