├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README_EN.md ├── demo.py ├── lunar_python ├── EightChar.py ├── Foto.py ├── FotoFestival.py ├── Fu.py ├── Holiday.py ├── JieQi.py ├── Lunar.py ├── LunarMonth.py ├── LunarTime.py ├── LunarYear.py ├── NineStar.py ├── ShuJiu.py ├── Solar.py ├── SolarHalfYear.py ├── SolarMonth.py ├── SolarSeason.py ├── SolarWeek.py ├── SolarYear.py ├── Tao.py ├── TaoFestival.py ├── __init__.py ├── eightchar │ ├── DaYun.py │ ├── LiuNian.py │ ├── LiuYue.py │ ├── XiaoYun.py │ ├── Yun.py │ └── __init__.py └── util │ ├── FotoUtil.py │ ├── HolidayUtil.py │ ├── LunarUtil.py │ ├── ShouXingUtil.py │ ├── SolarUtil.py │ ├── TaoUtil.py │ └── __init__.py ├── setup.py └── test ├── ChineseTest.py ├── EightCharTest.py ├── FotoTest.py ├── HolidayTest.py ├── HouTest.py ├── JieQiTest.py ├── LunarMonthTest.py ├── LunarTest.py ├── NineStarTest.py ├── ShuJiuTest.py ├── SolarMonthTest.py ├── SolarSeasonTest.py ├── SolarTest.py ├── SolarWeekTest.py ├── SolarYearTest.py ├── TaoTest.py ├── WeekTest.py ├── WuHouTest.py ├── XingZuoTest.py ├── XunTest.py ├── YearTest.py └── YunTest.py /.gitignore: -------------------------------------------------------------------------------- 1 | # general things to ignore 2 | build/ 3 | dist/ 4 | .idea/ 5 | venv/ 6 | *.egg-info/ 7 | *.egg 8 | *.py[cod] 9 | __pycache__/ 10 | *.so 11 | *~ 12 | 13 | # due to using tox and pytest 14 | .tox 15 | .cache 16 | .DS_Store -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 4 | ## [1.3.9] - 2024-03-01 5 | 1. 修复节气当天获取下一节气仍为当前节气的问题。 6 | 2. 修复每日宜忌存在重复项的问题。 7 | 3. 八字转阳历结果按时间先后排序,转换速度大幅提升。 8 | 9 | ## [1.3.10] - 2024-03-17 10 | 1. 修复八字转阳历存在遗漏的问题。 11 | 12 | ## [1.3.11] - 2024-11-12 13 | 1. 新增2025年法定假日数据。 14 | 15 | ## [1.3.12] - 2024-11-13 16 | 1. 修复小运干支错误。 17 | 18 | ## [1.4.0] - 2025-02-12 19 | 1. 修复九星错别字。 20 | 2. 修复每日宜忌错别字。 21 | 3. 去除每日宜忌的重复项。 22 | 23 | ## [1.4.1] - 2025-03-06 24 | 1. 调整每日宜忌默认流派。 25 | 2. 更新2018之后的△T参数。 26 | 27 | ## [1.4.3] - 2025-04-07 28 | 1. 修复个别日太岁方位的错误。 29 | 2. 修复八字身宫计算错误的问题。 30 | 31 | ## [1.4.4] - 2025-04-29 32 | 1. 修复身宫报错的问题。 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 6tail 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lunar [](https://github.com/6tail/lunar-python/blob/master/LICENSE) 2 | 3 | lunar是一款无第三方依赖的公历(阳历)、农历(阴历、老黄历)、佛历和道历工具,支持星座、儒略日、干支、生肖、节气、节日、彭祖百忌、吉神(喜神/福神/财神/阳贵神/阴贵神)方位、胎神方位、冲煞、纳音、星宿、八字、五行、十神、建除十二值星、青龙名堂等十二神、黄道日及吉凶、法定节假日及调休等。 4 | 5 | > v1.2.23起不再兼容python2。 6 | 7 | [English](https://github.com/6tail/lunar-python/blob/master/README_EN.md) 8 | 9 | ## 示例 10 | 11 | $ pip install lunar_python 12 | 13 | from lunar_python import Lunar 14 | 15 | # 通过指定年月日初始化阴历 16 | lunar = Lunar.fromYmd(1986, 4, 21) 17 | 18 | # 打印阴历 19 | print(lunar.toFullString()) 20 | 21 | # 阴历转阳历并打印 22 | print(lunar.getSolar().toFullString()) 23 | 24 | 输出结果: 25 | 26 | 一九八六年四月廿一 丙寅(虎)年 癸巳(蛇)月 癸酉(鸡)日 子(鼠)时 纳音[炉中火 长流水 剑锋金 桑柘木] 星期四 北方玄武 星宿[斗木獬](吉) 彭祖百忌[癸不词讼理弱敌强 酉不会客醉坐颠狂] 喜神方位[巽](东南) 阳贵神方位[巽](东南) 阴贵神方位[震](正东) 福神方位[兑](正西) 财神方位[离](正南) 冲[(丁卯)兔] 煞[东] 27 | 1986-05-29 00:00:00 星期四 双子座 28 | 29 | ## 文档 30 | 31 | 请移步至 [https://6tail.cn/calendar/api.html](https://6tail.cn/calendar/api.html "https://6tail.cn/calendar/api.html") 32 | 33 | ## Star History 34 | 35 | [](https://star-history.com/#6tail/lunar-python&Date) 36 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | # lunar [](https://github.com/6tail/lunar-python/blob/master/LICENSE) 2 | 3 | lunar is a calendar library for Solar and Chinese Lunar. 4 | 5 | > Python2 not supported since v1.2.23. 6 | 7 | [简体中文](https://github.com/6tail/lunar-python/blob/master/README.md) 8 | 9 | ## Example 10 | 11 | $ pip install lunar_python 12 | 13 | from lunar_python import Lunar 14 | 15 | # init lunar by ymd 16 | lunar = Lunar.fromYmd(1986, 4, 21) 17 | 18 | # print lunar 19 | print(lunar.toFullString()) 20 | 21 | # convert to solar and print 22 | print(lunar.getSolar().toFullString()) 23 | 24 | Output: 25 | 26 | 一九八六年四月廿一 丙寅(虎)年 癸巳(蛇)月 癸酉(鸡)日 子(鼠)时 纳音[炉中火 长流水 剑锋金 桑柘木] 星期四 北方玄武 星宿[斗木獬](吉) 彭祖百忌[癸不词讼理弱敌强 酉不会客醉坐颠狂] 喜神方位[巽](东南) 阳贵神方位[巽](东南) 阴贵神方位[震](正东) 福神方位[兑](正西) 财神方位[离](正南) 冲[(丁卯)兔] 煞[东] 27 | 1986-05-29 00:00:00 星期四 双子座 28 | 29 | ## Documentation 30 | 31 | Please visit [https://6tail.cn/calendar/api.html](https://6tail.cn/calendar/api.html "https://6tail.cn/calendar/api.html") 32 | 33 | ## Star History 34 | 35 | [](https://star-history.com/#6tail/lunar-python&Date) 36 | -------------------------------------------------------------------------------- /demo.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from lunar_python import Lunar, Solar 3 | from lunar_python.util import HolidayUtil 4 | from datetime import datetime 5 | 6 | # 节气表 7 | lunar = Solar.fromYmd(2022, 7, 15).getLunar() 8 | jieQi = lunar.getJieQiTable() 9 | for k in lunar.getJieQiList(): 10 | print(k + ' = ' + jieQi[k].toYmdHms()) 11 | print('') 12 | 13 | # 八字 14 | baZi = lunar.getEightChar() 15 | print(baZi.getYear() + ' ' + baZi.getMonth() + ' ' + baZi.getDay() + ' ' + baZi.getTime()) 16 | 17 | # 八字五行 18 | print(baZi.getYearWuXing() + ' ' + baZi.getMonthWuXing() + ' ' + baZi.getDayWuXing() + ' ' + baZi.getTimeWuXing()) 19 | 20 | # 八字天干十神 21 | print(baZi.getYearShiShenGan() + ' ' + baZi.getMonthShiShenGan() + ' ' + baZi.getDayShiShenGan() + ' ' + baZi.getTimeShiShenGan()) 22 | 23 | # 八字地支十神 24 | print(baZi.getYearShiShenZhi()[0] + ' ' + baZi.getMonthShiShenZhi()[0] + ' ' + baZi.getDayShiShenZhi()[0] + ' ' + baZi.getTimeShiShenZhi()[0]) 25 | 26 | # 遍历八字年支十神 27 | for v in baZi.getYearShiShenZhi(): 28 | print(v) 29 | print('') 30 | 31 | # 遍历八字月支十神 32 | for v in baZi.getMonthShiShenZhi(): 33 | print(v) 34 | print('') 35 | 36 | # 遍历八字日支十神 37 | for v in baZi.getDayShiShenZhi(): 38 | print(v) 39 | print('') 40 | 41 | # 遍历八字时支十神 42 | for v in baZi.getTimeShiShenZhi(): 43 | print(v) 44 | print('') 45 | 46 | solar = Solar(1988, 2, 15, 23, 30, 0) 47 | lunar = solar.getLunar() 48 | baZi = lunar.getEightChar() 49 | print(baZi.getYear() + ' ' + baZi.getMonth() + ' ' + baZi.getDay() + ' ' + baZi.getTime()) 50 | 51 | solar = Solar(1983, 2, 15, 20, 0, 0) 52 | lunar = solar.getLunar() 53 | baZi = lunar.getEightChar() 54 | 55 | # 女运 56 | yun = baZi.getYun(0) 57 | print('阳历' + solar.toYmdHms() + '出生') 58 | print('出生' + str(yun.getStartYear()) + '年' + str(yun.getStartMonth()) + '个月' + str(yun.getStartDay()) + '天后起运') 59 | print('阳历' + yun.getStartSolar().toYmd() + '后起运') 60 | print('') 61 | 62 | # 大运 63 | daYunArr = yun.getDaYun() 64 | for i in range(0, len(daYunArr)): 65 | daYun = daYunArr[i] 66 | print('大运[' + str(i) + '] ' + str(daYun.getStartYear()) + '年 ' + str(daYun.getStartAge()) + '岁 ' + daYun.getGanZhi()) 67 | print('') 68 | 69 | # 大运[0] 流年 70 | liuNianArr = daYunArr[0].getLiuNian() 71 | for i in range(0, len(liuNianArr)): 72 | liuNian = liuNianArr[i] 73 | print('流年[' + str(i) + '] ' + str(liuNian.getYear()) + '年 ' + str(liuNian.getAge()) + '岁 ' + liuNian.getGanZhi()) 74 | print('') 75 | 76 | # 大运[0] 小运 77 | xiaoYunArr = daYunArr[0].getXiaoYun() 78 | for i in range(0, len(xiaoYunArr)): 79 | xiaoYun = xiaoYunArr[i] 80 | print('小运[' + str(i) + '] ' + str(xiaoYun.getYear()) + '年 ' + str(xiaoYun.getAge()) + '岁 ' + xiaoYun.getGanZhi()) 81 | print('') 82 | 83 | # 流年[0] 流月 84 | liuYueArr = liuNianArr[0].getLiuYue() 85 | for i in range(0, len(liuYueArr)): 86 | liuYue = liuYueArr[i] 87 | print('流月[' + str(i) + '] ' + str(liuYue.getMonthInChinese()) + '月 ' + liuYue.getGanZhi()) 88 | print('') 89 | 90 | # 通过指定年月日初始化阴历 91 | lunar = Lunar.fromYmd(1986, 4, 21) 92 | 93 | # 打印阴历 94 | print(lunar.toFullString()) 95 | 96 | # 阴历转阳历并打印 97 | print(lunar.getSolar().toFullString()) 98 | 99 | # 节假日信息 100 | print(HolidayUtil.getHoliday('2020-05-02')) 101 | 102 | # 儒略日 103 | solar = Solar.fromYmd(2020, 7, 15) 104 | print(solar.getJulianDay()) 105 | 106 | solar = Solar.fromJulianDay(2459045.5) 107 | print(solar.toYmdHms()) 108 | print('') 109 | 110 | # 八字转阳历 111 | for d in Solar.fromBaZi("庚子", "戊子", "己卯", "庚午"): 112 | print(d.toFullString()) 113 | 114 | date = Solar.fromYmd(2020, 1, 23) 115 | print("2020-01-24" == date.next(1).toString()) 116 | # 仅工作日,跨越春节假期 117 | print("2020-02-03" == date.next(1, True).toString()) 118 | 119 | date = Solar.fromYmd(2020, 2, 3) 120 | print("2020-01-31" == date.next(-3).toString()) 121 | # 仅工作日,跨越春节假期 122 | print("2020-01-21" == date.next(-3, True).toString()) 123 | 124 | date = Solar.fromYmd(2020, 2, 9) 125 | print("2020-02-15" == date.next(6).toString()) 126 | # 仅工作日,跨越周末 127 | print("2020-02-17" == date.next(6, True).toString()) 128 | 129 | date = Solar.fromYmd(2020, 1, 17) 130 | print("2020-01-18" == date.next(1).toString()) 131 | # 仅工作日,周日调休按上班算 132 | print("2020-01-19" == date.next(1, True).toString()) 133 | 134 | print("2020-01-01 元旦节 2020-01-01" == HolidayUtil.getHoliday("2020-01-01").toString()) 135 | 136 | # 将2020-01-01修改为春节 137 | HolidayUtil.fix(None, "202001011120200101") 138 | print("2020-01-01 春节 2020-01-01" == HolidayUtil.getHoliday("2020-01-01").toString()) 139 | 140 | # 追加2099-01-01为元旦节 141 | HolidayUtil.fix(None, "209901010120990101") 142 | print("2099-01-01 元旦节 2099-01-01" == HolidayUtil.getHoliday("2099-01-01").toString()) 143 | 144 | # 将2020-01-01修改为春节,并追加2099-01-01为元旦节 145 | HolidayUtil.fix(None, "202001011120200101209901010120990101") 146 | print("2020-01-01 春节 2020-01-01" == HolidayUtil.getHoliday("2020-01-01").toString()) 147 | print("2099-01-01 元旦节 2099-01-01" == HolidayUtil.getHoliday("2099-01-01").toString()) 148 | 149 | # 更改节假日名称 150 | names = [] 151 | for i in range(0, len(HolidayUtil.NAMES)): 152 | names.append(HolidayUtil.NAMES[i]) 153 | names[0] = "元旦" 154 | names[1] = "大年初一" 155 | 156 | HolidayUtil.fix(names, None) 157 | print("2020-01-01 大年初一 2020-01-01" == HolidayUtil.getHoliday("2020-01-01").toString()) 158 | print("2099-01-01 元旦 2099-01-01" == HolidayUtil.getHoliday("2099-01-01").toString()) 159 | 160 | # 追加节假日名称和数据 161 | names = [] 162 | for i in range(0, len(HolidayUtil.NAMES)): 163 | names.append(HolidayUtil.NAMES[i]) 164 | names.append("我的生日") 165 | names.append("结婚纪念日") 166 | names.append("她的生日") 167 | 168 | HolidayUtil.fix(names, "20210529912021052920211111:12021111120211201;120211201") 169 | print("2021-05-29 我的生日 2021-05-29" == HolidayUtil.getHoliday("2021-05-29").toString()) 170 | print("2021-11-11 结婚纪念日 2021-11-11" == HolidayUtil.getHoliday("2021-11-11").toString()) 171 | print("2021-12-01 她的生日 2021-12-01" == HolidayUtil.getHoliday("2021-12-01").toString()) 172 | 173 | # 节日 174 | solar = Solar.fromYmd(2020, 11, 26) 175 | festivals = solar.getFestivals() 176 | for i in range(0, len(festivals)): 177 | print(festivals[i]) 178 | 179 | solar = Solar.fromYmd(2020, 6, 21) 180 | festivals = solar.getFestivals() 181 | for i in range(0, len(festivals)): 182 | print(festivals[i]) 183 | 184 | solar = Solar.fromYmd(2021, 5, 9) 185 | festivals = solar.getFestivals() 186 | for i in range(0, len(festivals)): 187 | print(festivals[i]) 188 | 189 | solar = Solar.fromYmd(1986, 11, 27) 190 | festivals = solar.getFestivals() 191 | for i in range(0, len(festivals)): 192 | print(festivals[i]) 193 | 194 | solar = Solar.fromYmd(1985, 6, 16) 195 | festivals = solar.getFestivals() 196 | for i in range(0, len(festivals)): 197 | print(festivals[i]) 198 | 199 | solar = Solar.fromYmd(1984, 5, 13) 200 | festivals = solar.getFestivals() 201 | for i in range(0, len(festivals)): 202 | print(festivals[i]) 203 | 204 | # 旬 205 | solar = Solar.fromYmdHms(2020, 11, 19, 0, 0, 0) 206 | lunar = solar.getLunar() 207 | # 甲午 208 | print(lunar.getYearXun()) 209 | 210 | # 旬空(空亡) 211 | # 辰巳 212 | print(lunar.getYearXunKong()) 213 | # 午未 214 | print(lunar.getMonthXunKong()) 215 | # 戌亥 216 | print(lunar.getDayXunKong()) 217 | 218 | # 八字日柱旬空(空亡) 219 | solar = Solar.fromYmdHms(1990, 12, 23, 8, 37, 0) 220 | lunar = solar.getLunar() 221 | eightChar = lunar.getEightChar() 222 | # 子丑 223 | print(eightChar.getDayXunKong()) 224 | 225 | # 数九 226 | lunar = Lunar.fromDate(datetime.now()) 227 | print(lunar.getShuJiu()) 228 | 229 | # 三伏 230 | solar = Solar.fromYmd(2020, 8, 24) 231 | lunar = solar.getLunar() 232 | print(lunar.getFu().toFullString()) 233 | 234 | # 六曜 235 | lunar = Lunar.fromDate(datetime.now()) 236 | print(lunar.getLiuYao()) 237 | 238 | # 物候 239 | print(lunar.getWuHou()) 240 | 241 | # 日九星 242 | print(lunar.getDayNineStar()) 243 | 244 | # 年太岁 245 | print(lunar.getYearPositionTaiSui()) 246 | print(lunar.getYearPositionTaiSuiDesc()) 247 | 248 | # 月太岁 249 | print(lunar.getMonthPositionTaiSui()) 250 | print(lunar.getMonthPositionTaiSuiDesc()) 251 | 252 | # 日太岁 253 | print(lunar.getDayPositionTaiSui()) 254 | print(lunar.getDayPositionTaiSuiDesc()) 255 | 256 | times = lunar.getTimes() 257 | for i in range(0, len(times)): 258 | time = times[i] 259 | print("%s - %s : %s" % (time.getMinHm(), time.getMaxHm(), time.toString())) 260 | -------------------------------------------------------------------------------- /lunar_python/EightChar.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from .util import LunarUtil 3 | 4 | 5 | class EightChar: 6 | """ 7 | 八字 8 | """ 9 | 10 | MONTH_ZHI = ("", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥", "子", "丑") 11 | 12 | CHANG_SHENG = ("长生", "沐浴", "冠带", "临官", "帝旺", "衰", "病", "死", "墓", "绝", "胎", "养") 13 | 14 | __CHANG_SHENG_OFFSET = { 15 | "甲": 1, 16 | "丙": 10, 17 | "戊": 10, 18 | "庚": 7, 19 | "壬": 4, 20 | "乙": 6, 21 | "丁": 9, 22 | "己": 9, 23 | "辛": 0, 24 | "癸": 3 25 | } 26 | 27 | def __init__(self, lunar): 28 | self.__sect = 2 29 | self.__lunar = lunar 30 | 31 | @staticmethod 32 | def fromLunar(lunar): 33 | return EightChar(lunar) 34 | 35 | def toString(self): 36 | return self.getYear() + " " + self.getMonth() + " " + self.getDay() + " " + self.getTime() 37 | 38 | def __str__(self): 39 | return self.toString() 40 | 41 | def getSect(self): 42 | return self.__sect 43 | 44 | def setSect(self, sect): 45 | self.__sect = sect 46 | 47 | def getYear(self): 48 | """ 49 | 获取年柱 50 | :return: 年柱 51 | """ 52 | return self.__lunar.getYearInGanZhiExact() 53 | 54 | def getYearGan(self): 55 | """ 56 | 获取年干 57 | :return: 天干 58 | """ 59 | return self.__lunar.getYearGanExact() 60 | 61 | def getYearZhi(self): 62 | """ 63 | 获取年支 64 | :return: 地支 65 | """ 66 | return self.__lunar.getYearZhiExact() 67 | 68 | def getYearHideGan(self): 69 | """ 70 | 获取年柱地支藏干,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 71 | :return: 天干 72 | """ 73 | return LunarUtil.ZHI_HIDE_GAN.get(self.getYearZhi()) 74 | 75 | def getYearWuXing(self): 76 | """ 77 | 获取年柱五行 78 | :return: 五行 79 | """ 80 | return LunarUtil.WU_XING_GAN.get(self.getYearGan()) + LunarUtil.WU_XING_ZHI.get(self.getYearZhi()) 81 | 82 | def getYearNaYin(self): 83 | """ 84 | 获取年柱纳音 85 | :return: 纳音 86 | """ 87 | return LunarUtil.NAYIN.get(self.getYear()) 88 | 89 | def getYearShiShenGan(self): 90 | """ 91 | 获取年柱天干十神 92 | :return: 十神 93 | """ 94 | return LunarUtil.SHI_SHEN.get(self.getDayGan() + self.getYearGan()) 95 | 96 | def __getShiShenZhi(self, zhi): 97 | hide_gan = LunarUtil.ZHI_HIDE_GAN.get(zhi) 98 | arr = [] 99 | for gan in hide_gan: 100 | arr.append(LunarUtil.SHI_SHEN.get(self.getDayGan() + gan)) 101 | return arr 102 | 103 | def getYearShiShenZhi(self): 104 | """ 105 | 获取年柱地支十神,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 106 | :return: 十神 107 | """ 108 | return self.__getShiShenZhi(self.getYearZhi()) 109 | 110 | def getDayGanIndex(self): 111 | return self.__lunar.getDayGanIndexExact2() if 2 == self.__sect else self.__lunar.getDayGanIndexExact() 112 | 113 | def getDayZhiIndex(self): 114 | return self.__lunar.getDayZhiIndexExact2() if 2 == self.__sect else self.__lunar.getDayZhiIndexExact() 115 | 116 | def __getDiShi(self, zhi_index): 117 | index = self.__CHANG_SHENG_OFFSET.get(self.getDayGan()) + (zhi_index if self.getDayGanIndex() % 2 == 0 else -zhi_index) 118 | if index >= 12: 119 | index -= 12 120 | if index < 0: 121 | index += 12 122 | return EightChar.CHANG_SHENG[index] 123 | 124 | def getYearDiShi(self): 125 | """ 126 | 获取年柱地势(长生十二神) 127 | :return: 地势 128 | """ 129 | return self.__getDiShi(self.__lunar.getYearZhiIndexExact()) 130 | 131 | def getMonth(self): 132 | """ 133 | 获取月柱 134 | :return: 月柱 135 | """ 136 | return self.__lunar.getMonthInGanZhiExact() 137 | 138 | def getMonthGan(self): 139 | """ 140 | 获取月干 141 | :return: 天干 142 | """ 143 | return self.__lunar.getMonthGanExact() 144 | 145 | def getMonthZhi(self): 146 | """ 147 | 获取月支 148 | :return: 地支 149 | """ 150 | return self.__lunar.getMonthZhiExact() 151 | 152 | def getMonthHideGan(self): 153 | """ 154 | 获取月柱地支藏干,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 155 | :return: 天干 156 | """ 157 | return LunarUtil.ZHI_HIDE_GAN.get(self.getMonthZhi()) 158 | 159 | def getMonthWuXing(self): 160 | """ 161 | 获取月柱五行 162 | :return: 五行 163 | """ 164 | return LunarUtil.WU_XING_GAN.get(self.getMonthGan()) + LunarUtil.WU_XING_ZHI.get(self.getMonthZhi()) 165 | 166 | def getMonthNaYin(self): 167 | """ 168 | 获取月柱纳音 169 | :return: 纳音 170 | """ 171 | return LunarUtil.NAYIN.get(self.getMonth()) 172 | 173 | def getMonthShiShenGan(self): 174 | """ 175 | 获取月柱天干十神 176 | :return: 十神 177 | """ 178 | return LunarUtil.SHI_SHEN.get(self.getDayGan() + self.getMonthGan()) 179 | 180 | def getMonthShiShenZhi(self): 181 | """ 182 | 获取月柱地支十神,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 183 | :return: 十神 184 | """ 185 | return self.__getShiShenZhi(self.getMonthZhi()) 186 | 187 | def getMonthDiShi(self): 188 | """ 189 | 获取月柱地势(长生十二神) 190 | :return: 地势 191 | """ 192 | return self.__getDiShi(self.__lunar.getMonthZhiIndexExact()) 193 | 194 | def getDay(self): 195 | """ 196 | 获取日柱 197 | :return: 日柱 198 | """ 199 | return self.__lunar.getDayInGanZhiExact2() if 2 == self.__sect else self.__lunar.getDayInGanZhiExact() 200 | 201 | def getDayGan(self): 202 | """ 203 | 获取日干 204 | :return: 天干 205 | """ 206 | return self.__lunar.getDayGanExact2() if 2 == self.__sect else self.__lunar.getDayGanExact() 207 | 208 | def getDayZhi(self): 209 | """ 210 | 获取日支 211 | :return: 地支 212 | """ 213 | return self.__lunar.getDayZhiExact2() if 2 == self.__sect else self.__lunar.getDayZhiExact() 214 | 215 | def getDayHideGan(self): 216 | """ 217 | 获取日柱地支藏干,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 218 | :return: 天干 219 | """ 220 | return LunarUtil.ZHI_HIDE_GAN.get(self.getDayZhi()) 221 | 222 | def getDayWuXing(self): 223 | """ 224 | 获取日柱五行 225 | :return: 五行 226 | """ 227 | return LunarUtil.WU_XING_GAN.get(self.getDayGan()) + LunarUtil.WU_XING_ZHI.get(self.getDayZhi()) 228 | 229 | def getDayNaYin(self): 230 | """ 231 | 获取日柱纳音 232 | :return: 纳音 233 | """ 234 | return LunarUtil.NAYIN.get(self.getDay()) 235 | 236 | def getDayShiShenGan(self): 237 | """ 238 | 获取日柱天干十神,也称日元、日干 239 | :return: 十神 240 | """ 241 | return "日主" 242 | 243 | def getDayShiShenZhi(self): 244 | """ 245 | 获取日柱地支十神,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 246 | :return: 十神 247 | """ 248 | return self.__getShiShenZhi(self.getDayZhi()) 249 | 250 | def getDayDiShi(self): 251 | """ 252 | 获取日柱地势(长生十二神) 253 | :return: 地势 254 | """ 255 | return self.__getDiShi(self.getDayZhiIndex()) 256 | 257 | def getTime(self): 258 | """ 259 | 获取时柱 260 | :return: 时柱 261 | """ 262 | return self.__lunar.getTimeInGanZhi() 263 | 264 | def getTimeGan(self): 265 | """ 266 | 获取时干 267 | :return: 天干 268 | """ 269 | return self.__lunar.getTimeGan() 270 | 271 | def getTimeZhi(self): 272 | """ 273 | 获取时支 274 | :return: 地支 275 | """ 276 | return self.__lunar.getTimeZhi() 277 | 278 | def getTimeHideGan(self): 279 | """ 280 | 获取时柱地支藏干,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 281 | :return: 天干 282 | """ 283 | return LunarUtil.ZHI_HIDE_GAN.get(self.getTimeZhi()) 284 | 285 | def getTimeWuXing(self): 286 | """ 287 | 获取时柱五行 288 | :return: 五行 289 | """ 290 | return LunarUtil.WU_XING_GAN.get(self.getTimeGan()) + LunarUtil.WU_XING_ZHI.get(self.getTimeZhi()) 291 | 292 | def getTimeNaYin(self): 293 | """ 294 | 获取时柱纳音 295 | :return: 纳音 296 | """ 297 | return LunarUtil.NAYIN.get(self.getTime()) 298 | 299 | def getTimeShiShenGan(self): 300 | """ 301 | 获取时柱天干十神 302 | :return: 十神 303 | """ 304 | return LunarUtil.SHI_SHEN.get(self.getDayGan() + self.getTimeGan()) 305 | 306 | def getTimeShiShenZhi(self): 307 | """ 308 | 获取时柱地支十神,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 309 | :return: 十神 310 | """ 311 | return self.__getShiShenZhi(self.getTimeZhi()) 312 | 313 | def getTimeDiShi(self): 314 | """ 315 | 获取时柱地势(长生十二神) 316 | :return: 地势 317 | """ 318 | return self.__getDiShi(self.__lunar.getTimeZhiIndex()) 319 | 320 | def getTaiYuan(self): 321 | """ 322 | 获取胎元 323 | :return: 胎元 324 | """ 325 | gan_index = self.__lunar.getMonthGanIndexExact() + 1 326 | if gan_index >= 10: 327 | gan_index -= 10 328 | zhi_index = self.__lunar.getMonthZhiIndexExact() + 3 329 | if zhi_index >= 12: 330 | zhi_index -= 12 331 | return LunarUtil.GAN[gan_index + 1] + LunarUtil.ZHI[zhi_index + 1] 332 | 333 | def getTaiYuanNaYin(self): 334 | """ 335 | 获取胎元纳音 336 | :return: 纳音 337 | """ 338 | return LunarUtil.NAYIN.get(self.getTaiYuan()) 339 | 340 | def getTaiXi(self): 341 | """ 342 | 获取胎息 343 | :return: 胎息 344 | """ 345 | gan_index = self.__lunar.getDayGanIndexExact2() if 2 == self.__sect else self.__lunar.getDayGanIndexExact() 346 | zhi_index = self.__lunar.getDayZhiIndexExact2() if 2 == self.__sect else self.__lunar.getDayZhiIndexExact() 347 | return LunarUtil.HE_GAN_5[gan_index] + LunarUtil.HE_ZHI_6[zhi_index] 348 | 349 | def getTaiXiNaYin(self): 350 | """ 351 | 获取胎息纳音 352 | :return: 纳音 353 | """ 354 | return LunarUtil.NAYIN.get(self.getTaiXi()) 355 | 356 | def getMingGong(self): 357 | """ 358 | 获取命宫 359 | :return: 命宫 360 | """ 361 | month_zhi_index = 0 362 | time_zhi_index = 0 363 | month_zhi = self.getMonthZhi() 364 | time_zhi = self.getTimeZhi() 365 | for i in range(0, len(EightChar.MONTH_ZHI)): 366 | zhi = EightChar.MONTH_ZHI[i] 367 | if month_zhi == zhi: 368 | month_zhi_index = i 369 | break 370 | for i in range(0, len(EightChar.MONTH_ZHI)): 371 | zhi = EightChar.MONTH_ZHI[i] 372 | if time_zhi == zhi: 373 | time_zhi_index = i 374 | break 375 | offset = month_zhi_index + time_zhi_index 376 | if offset >= 14: 377 | offset = 26 - offset 378 | else: 379 | offset = 14 - offset 380 | gan_index = (self.__lunar.getYearGanIndexExact() + 1) * 2 + offset 381 | while gan_index > 10: 382 | gan_index -= 10 383 | return LunarUtil.GAN[gan_index] + EightChar.MONTH_ZHI[offset] 384 | 385 | def getMingGongNaYin(self): 386 | """ 387 | 获取命宫纳音 388 | :return: 纳音 389 | """ 390 | return LunarUtil.NAYIN.get(self.getMingGong()) 391 | 392 | def getShenGong(self): 393 | """ 394 | 获取身宫 395 | :return: 身宫 396 | """ 397 | month_zhi_index = 0 398 | time_zhi_index = 0 399 | month_zhi = self.getMonthZhi() 400 | time_zhi = self.getTimeZhi() 401 | for i in range(0, len(EightChar.MONTH_ZHI)): 402 | zhi = EightChar.MONTH_ZHI[i] 403 | if month_zhi == zhi: 404 | month_zhi_index = i 405 | break 406 | for i in range(0, len(LunarUtil.ZHI)): 407 | zhi = LunarUtil.ZHI[i] 408 | if time_zhi == zhi: 409 | time_zhi_index = i 410 | break 411 | offset = month_zhi_index + time_zhi_index 412 | if offset > 12: 413 | offset -= 12 414 | gan_index = (self.__lunar.getYearGanIndexExact() + 1) * 2 + offset 415 | while gan_index > 10: 416 | gan_index -= 10 417 | return LunarUtil.GAN[gan_index] + EightChar.MONTH_ZHI[offset] 418 | 419 | def getShenGongNaYin(self): 420 | """ 421 | 获取身宫纳音 422 | :return: 纳音 423 | """ 424 | return LunarUtil.NAYIN.get(self.getShenGong()) 425 | 426 | def getLunar(self): 427 | return self.__lunar 428 | 429 | def getYun(self, gender, sect=1): 430 | """ 431 | 获取运 432 | :param gender: 性别:1男,0女 433 | :param sect 流派:1按天数和时辰数计算,3天1年,1天4个月,1时辰10天;2按分钟数计算 434 | :return: 运 435 | """ 436 | from .eightchar import Yun 437 | return Yun(self, gender, sect) 438 | 439 | def getYearXun(self): 440 | """ 441 | 获取年柱所在旬 442 | :return: 旬 443 | """ 444 | return self.__lunar.getYearXunExact() 445 | 446 | def getYearXunKong(self): 447 | """ 448 | 获取年柱旬空(空亡) 449 | :return: 旬空(空亡) 450 | """ 451 | return self.__lunar.getYearXunKongExact() 452 | 453 | def getMonthXun(self): 454 | """ 455 | 获取月柱所在旬 456 | :return: 旬 457 | """ 458 | return self.__lunar.getMonthXunExact() 459 | 460 | def getMonthXunKong(self): 461 | """ 462 | 获取月柱旬空(空亡) 463 | :return: 旬空(空亡) 464 | """ 465 | return self.__lunar.getMonthXunKongExact() 466 | 467 | def getDayXun(self): 468 | """ 469 | 获取日柱所在旬 470 | :return: 旬 471 | """ 472 | return self.__lunar.getDayXunExact2() if 2 == self.__sect else self.__lunar.getDayXunExact() 473 | 474 | def getDayXunKong(self): 475 | """ 476 | 获取日柱旬空(空亡) 477 | :return: 旬空(空亡) 478 | """ 479 | return self.__lunar.getDayXunKongExact2() if 2 == self.__sect else self.__lunar.getDayXunKongExact() 480 | 481 | def getTimeXun(self): 482 | """ 483 | 获取时柱所在旬 484 | :return: 旬 485 | """ 486 | return self.__lunar.getTimeXun() 487 | 488 | def getTimeXunKong(self): 489 | """ 490 | 获取时柱旬空(空亡) 491 | :return: 旬空(空亡) 492 | """ 493 | return self.__lunar.getTimeXunKong() 494 | -------------------------------------------------------------------------------- /lunar_python/Foto.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from . import Lunar, LunarMonth 3 | from .util import LunarUtil, FotoUtil 4 | 5 | 6 | class Foto: 7 | """ 8 | 佛历 9 | """ 10 | 11 | DEAD_YEAR = -543 12 | 13 | def __init__(self, lunar): 14 | self.__lunar = lunar 15 | 16 | @staticmethod 17 | def fromLunar(lunar): 18 | return Foto(lunar) 19 | 20 | @staticmethod 21 | def fromYmdHms(year, month, day, hour, minute, second): 22 | return Foto.fromLunar(Lunar.fromYmdHms(year + Foto.DEAD_YEAR - 1, month, day, hour, minute, second)) 23 | 24 | @staticmethod 25 | def fromYmd(year, month, day): 26 | return Foto.fromYmdHms(year, month, day, 0, 0, 0) 27 | 28 | def getLunar(self): 29 | return self.__lunar 30 | 31 | def getYear(self): 32 | sy = self.__lunar.getSolar().getYear() 33 | y = sy - Foto.DEAD_YEAR 34 | if sy == self.__lunar.getYear(): 35 | y += 1 36 | return y 37 | 38 | def getMonth(self): 39 | return self.__lunar.getMonth() 40 | 41 | def getDay(self): 42 | return self.__lunar.getDay() 43 | 44 | def getYearInChinese(self): 45 | y = str(self.getYear()) 46 | s = "" 47 | for i in range(0, len(y)): 48 | s += LunarUtil.NUMBER[ord(y[i]) - 48] 49 | return s 50 | 51 | def getMonthInChinese(self): 52 | return self.__lunar.getMonthInChinese() 53 | 54 | def getDayInChinese(self): 55 | return self.__lunar.getDayInChinese() 56 | 57 | def getFestivals(self): 58 | festivals = [] 59 | md = "%d-%d" % (abs(self.getMonth()), self.getDay()) 60 | if md in FotoUtil.FESTIVAL: 61 | fs = FotoUtil.FESTIVAL[md] 62 | for f in fs: 63 | festivals.append(f) 64 | return festivals 65 | 66 | def getOtherFestivals(self): 67 | """ 68 | 获取纪念日 69 | :return: 非正式的节日列表,如中元节 70 | """ 71 | festivals = [] 72 | key = "%d-%d" % (self.getMonth(), self.getDay()) 73 | if key in FotoUtil.OTHER_FESTIVAL: 74 | for f in FotoUtil.OTHER_FESTIVAL[key]: 75 | festivals.append(f) 76 | return festivals 77 | 78 | def isMonthZhai(self): 79 | m = self.getMonth() 80 | return 1 == m or 5 == m or 9 == m 81 | 82 | def isDayYangGong(self): 83 | for f in self.getFestivals(): 84 | if "杨公忌" == f.getName(): 85 | return True 86 | return False 87 | 88 | def isDayZhaiShuoWang(self): 89 | d = self.getDay() 90 | return 1 == d or 15 == d 91 | 92 | def isDayZhaiSix(self): 93 | d = self.getDay() 94 | if 8 == d or 14 == d or 15 == d or 23 == d or 29 == d or 30 == d: 95 | return True 96 | elif 28 == d: 97 | m = LunarMonth.fromYm(self.__lunar.getYear(), self.getMonth()) 98 | return m is not None and 30 != m.getDayCount() 99 | return False 100 | 101 | def isDayZhaiTen(self): 102 | d = self.getDay() 103 | return 1 == d or 8 == d or 14 == d or 15 == d or 18 == d or 23 == d or 24 == d or 28 == d or 29 == d or 30 == d 104 | 105 | def isDayZhaiGuanYin(self): 106 | k = "%d-%d" % (self.getMonth(), self.getDay()) 107 | for d in FotoUtil.DAY_ZHAI_GUAN_YIN: 108 | if k == d: 109 | return True 110 | return False 111 | 112 | def getXiu(self): 113 | return FotoUtil.getXiu(self.getMonth(), self.getDay()) 114 | 115 | def getXiuLuck(self): 116 | return LunarUtil.XIU_LUCK[self.getXiu()] 117 | 118 | def getXiuSong(self): 119 | return LunarUtil.XIU_SONG[self.getXiu()] 120 | 121 | def getZheng(self): 122 | return LunarUtil.ZHENG[self.getXiu()] 123 | 124 | def getAnimal(self): 125 | return LunarUtil.ANIMAL[self.getXiu()] 126 | 127 | def getGong(self): 128 | return LunarUtil.GONG[self.getXiu()] 129 | 130 | def getShou(self): 131 | return LunarUtil.SHOU[self.getGong()] 132 | 133 | def __str__(self): 134 | return self.toString() 135 | 136 | def toString(self): 137 | return "%s年%s月%s" % (self.getYearInChinese(), self.getMonthInChinese(), self.getDayInChinese()) 138 | 139 | def toFullString(self): 140 | s = self.toString() 141 | for f in self.getFestivals(): 142 | s += " (%s)" % f 143 | return s 144 | -------------------------------------------------------------------------------- /lunar_python/FotoFestival.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class FotoFestival: 5 | """ 6 | 佛历因果犯忌 7 | """ 8 | 9 | def __init__(self, name, result=None, every_month=False, remark=None): 10 | self.__name = name 11 | self.__result = "" if result is None else result 12 | self.__everyMonth = every_month 13 | self.__remark = "" if remark is None else remark 14 | 15 | def getName(self): 16 | return self.__name 17 | 18 | def getResult(self): 19 | return self.__result 20 | 21 | def isEveryMonth(self): 22 | return self.__everyMonth 23 | 24 | def getRemark(self): 25 | return self.__remark 26 | 27 | def __str__(self): 28 | return self.toString() 29 | 30 | def toString(self): 31 | return self.__name 32 | 33 | def toFullString(self): 34 | s = self.__name 35 | if self.__result is not None and len(self.__result) > 0: 36 | s += " " + self.__result 37 | if self.__remark is not None and len(self.__remark) > 0: 38 | s += " " + self.__remark 39 | return s 40 | -------------------------------------------------------------------------------- /lunar_python/Fu.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class Fu: 5 | """ 6 | 三伏 7 |
从夏至后第3个庚日算起,初伏为10天,中伏为10天或20天,末伏为10天。当夏至与立秋之间出现4个庚日时中伏为10天,出现5个庚日则为20天。
8 | """ 9 | 10 | def __init__(self, name, index): 11 | self.__name = name 12 | self.__index = index 13 | 14 | def getName(self): 15 | return self.__name 16 | 17 | def setName(self, name): 18 | self.__name = name 19 | 20 | def getIndex(self): 21 | return self.__index 22 | 23 | def setIndex(self, index): 24 | self.__index = index 25 | 26 | def __str__(self): 27 | return self.toString() 28 | 29 | def toString(self): 30 | return self.__name 31 | 32 | def toFullString(self): 33 | return "%s第%d天" % (self.__name, self.__index) 34 | -------------------------------------------------------------------------------- /lunar_python/Holiday.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | class Holiday: 3 | """ 4 | 节假日 5 | """ 6 | 7 | def __init__(self, day, name, work, target): 8 | """ 9 | 初始化 10 | :param day: 日期,YYYY-MM-DD格式 11 | :param name: 名称,如:国庆 12 | :param work: 是否调休,即是否要上班 13 | :param target: 关联的节日,YYYY-MM-DD格式 14 | """ 15 | self.__day = Holiday.__ymd(day) 16 | self.__name = name 17 | self.__work = work 18 | self.__target = Holiday.__ymd(target) 19 | 20 | @staticmethod 21 | def __ymd(s): 22 | return s if "-" in s else (s[0:4] + "-" + s[4:6] + "-" + s[6:]) 23 | 24 | def getDay(self): 25 | return self.__day 26 | 27 | def getName(self): 28 | return self.__name 29 | 30 | def isWork(self): 31 | return self.__work 32 | 33 | def getTarget(self): 34 | return self.__target 35 | 36 | def setDay(self, day): 37 | self.__day = Holiday.__ymd(day) 38 | 39 | def setName(self, name): 40 | self.__name = name 41 | 42 | def setWork(self, work): 43 | self.__work = work 44 | 45 | def setTarget(self, target): 46 | self.__target = Holiday.__ymd(target) 47 | 48 | def toString(self): 49 | return "%s %s%s %s" % (self.__day, self.__name, "调休" if self.__work else "", self.__target) 50 | 51 | def __str__(self): 52 | return self.toString() 53 | -------------------------------------------------------------------------------- /lunar_python/JieQi.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class JieQi: 5 | """ 6 | 节气 7 | """ 8 | 9 | def __init__(self, name, solar): 10 | self.__name = name 11 | self.__jie = False 12 | self.__qi = False 13 | self.__solar = solar 14 | self.setName(name) 15 | 16 | def getName(self): 17 | """ 18 | 获取名称 19 | :return: 名称 20 | """ 21 | return self.__name 22 | 23 | def setName(self, name): 24 | """ 25 | 设置名称 26 | :param name: 名称 27 | """ 28 | from . import Lunar 29 | self.__name = name 30 | for i in range(0, len(Lunar.JIE_QI)): 31 | if name == Lunar.JIE_QI[i]: 32 | if i % 2 == 0: 33 | self.__qi = True 34 | else: 35 | self.__jie = True 36 | return 37 | 38 | def getSolar(self): 39 | """ 40 | 获取阳历日期 41 | :return: 阳历日期 42 | """ 43 | return self.__solar 44 | 45 | def setSolar(self, solar): 46 | """ 47 | 设置阳历日期 48 | :param solar: 阳历日期 49 | """ 50 | self.__solar = solar 51 | 52 | def isJie(self): 53 | """ 54 | 是否节令 55 | :return: true/false 56 | """ 57 | return self.__jie 58 | 59 | def isQi(self): 60 | """ 61 | 是否气令 62 | :return: true/false 63 | """ 64 | return self.__qi 65 | 66 | def toString(self): 67 | return self.__name 68 | 69 | def __str__(self): 70 | return self.toString() 71 | -------------------------------------------------------------------------------- /lunar_python/LunarMonth.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from . import Solar, LunarYear, NineStar 3 | from .util import LunarUtil 4 | 5 | 6 | class LunarMonth: 7 | """ 8 | 农历月 9 | """ 10 | 11 | def __init__(self, lunar_year, lunar_month, day_count, first_julian_day, index): 12 | self.__year = lunar_year 13 | self.__month = lunar_month 14 | self.__dayCount = day_count 15 | self.__firstJulianDay = first_julian_day 16 | self.__index = index 17 | self.__zhiIndex = (index - 1 + LunarUtil.BASE_MONTH_ZHI_INDEX) % 12 18 | 19 | @staticmethod 20 | def fromYm(lunar_year, lunar_month): 21 | from . import LunarYear 22 | return LunarYear.fromYear(lunar_year).getMonth(lunar_month) 23 | 24 | def getYear(self): 25 | return self.__year 26 | 27 | def getMonth(self): 28 | return self.__month 29 | 30 | def getIndex(self): 31 | return self.__index 32 | 33 | def getZhiIndex(self): 34 | return self.__zhiIndex 35 | 36 | def getGanIndex(self): 37 | offset = (LunarYear.fromYear(self.__year).getGanIndex() + 1) % 5 * 2 38 | return (self.__index - 1 + offset) % 10 39 | 40 | def getGan(self): 41 | return LunarUtil.GAN[self.getGanIndex() + 1] 42 | 43 | def getZhi(self): 44 | return LunarUtil.ZHI[self.getZhiIndex() + 1] 45 | 46 | def getGanZhi(self): 47 | return "%s%s" % (self.getGan(), self.getZhi()) 48 | 49 | def getPositionXi(self): 50 | return LunarUtil.POSITION_XI[self.getGanIndex() + 1] 51 | 52 | def getPositionXiDesc(self): 53 | return LunarUtil.POSITION_DESC[self.getPositionXi()] 54 | 55 | def getPositionYangGui(self): 56 | return LunarUtil.POSITION_YANG_GUI[self.getGanIndex() + 1] 57 | 58 | def getPositionYangGuiDesc(self): 59 | return LunarUtil.POSITION_DESC[self.getPositionYangGui()] 60 | 61 | def getPositionYinGui(self): 62 | return LunarUtil.POSITION_YIN_GUI[self.getGanIndex() + 1] 63 | 64 | def getPositionYinGuiDesc(self): 65 | return LunarUtil.POSITION_DESC[self.getPositionYinGui()] 66 | 67 | def getPositionFu(self, sect=2): 68 | return (LunarUtil.POSITION_FU if 1 == sect else LunarUtil.POSITION_FU_2)[self.getGanIndex() + 1] 69 | 70 | def getPositionFuDesc(self, sect=2): 71 | return LunarUtil.POSITION_DESC[self.getPositionFu(sect)] 72 | 73 | def getPositionCai(self): 74 | return LunarUtil.POSITION_CAI[self.getGanIndex() + 1] 75 | 76 | def getPositionCaiDesc(self): 77 | return LunarUtil.POSITION_DESC[self.getPositionCai()] 78 | 79 | def isLeap(self): 80 | return self.__month < 0 81 | 82 | def getDayCount(self): 83 | return self.__dayCount 84 | 85 | def getFirstJulianDay(self): 86 | return self.__firstJulianDay 87 | 88 | def getPositionTaiSui(self): 89 | m = abs(self.__month) % 4 90 | if 0 == m: 91 | p = "巽" 92 | elif 1 == m: 93 | p = "艮" 94 | elif 3 == m: 95 | p = "坤" 96 | else: 97 | p = LunarUtil.POSITION_GAN[Solar.fromJulianDay(self.getFirstJulianDay()).getLunar().getMonthGanIndex()] 98 | return p 99 | 100 | def getPositionTaiSuiDesc(self): 101 | return LunarUtil.POSITION_DESC[self.getPositionTaiSui()] 102 | 103 | def getNineStar(self): 104 | index = LunarYear.fromYear(self.__year).getZhiIndex() % 3 105 | m = abs(self.__month) 106 | month_zhi_index = (13 + m) % 12 107 | n = 27 - (index * 3) 108 | if month_zhi_index < LunarUtil.BASE_MONTH_ZHI_INDEX: 109 | n -= 3 110 | offset = (n - month_zhi_index) % 9 111 | return NineStar.fromIndex(offset) 112 | 113 | def toString(self): 114 | return "%d年%s%s月(%d天)" % (self.__year, ("闰" if self.isLeap() else ""), LunarUtil.MONTH[abs(self.__month)], self.__dayCount) 115 | 116 | def __str__(self): 117 | return self.toString() 118 | 119 | def next(self, n): 120 | """ 121 | 获取往后推几个月的阴历月,如果要往前推,则月数用负数 122 | :param n: 月数 123 | :return: 阴历月 124 | """ 125 | if 0 == n: 126 | return LunarMonth.fromYm(self.__year, self.__month) 127 | elif n > 0: 128 | rest = n 129 | ny = self.__year 130 | iy = ny 131 | im = self.__month 132 | index = 0 133 | months = LunarYear.fromYear(ny).getMonths() 134 | while True: 135 | size = len(months) 136 | for i in range(0, size): 137 | m = months[i] 138 | if m.getYear() == iy and m.getMonth() == im: 139 | index = i 140 | break 141 | more = size - index - 1 142 | if rest < more: 143 | break 144 | rest -= more 145 | last_month = months[size - 1] 146 | iy = last_month.getYear() 147 | im = last_month.getMonth() 148 | ny += 1 149 | months = LunarYear.fromYear(ny).getMonths() 150 | return months[index + rest] 151 | else: 152 | rest = -n 153 | ny = self.__year 154 | iy = ny 155 | im = self.__month 156 | index = 0 157 | months = LunarYear.fromYear(ny).getMonths() 158 | while True: 159 | size = len(months) 160 | for i in range(0, size): 161 | m = months[i] 162 | if m.getYear() == iy and m.getMonth() == im: 163 | index = i 164 | break 165 | if rest <= index: 166 | break 167 | rest -= index 168 | first_month = months[0] 169 | iy = first_month.getYear() 170 | im = first_month.getMonth() 171 | ny -= 1 172 | months = LunarYear.fromYear(ny).getMonths() 173 | return months[index - rest] 174 | -------------------------------------------------------------------------------- /lunar_python/LunarTime.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from . import NineStar 3 | from .util import LunarUtil 4 | 5 | 6 | class LunarTime: 7 | """ 8 | 时辰 9 | """ 10 | 11 | def __init__(self, lunar_year, lunar_month, lunar_day, hour, minute, second): 12 | from . import Lunar 13 | self.__lunar = Lunar.fromYmdHms(lunar_year, lunar_month, lunar_day, hour, minute, second) 14 | self.__zhiIndex = LunarUtil.getTimeZhiIndex("%02d:%02d" % (hour, minute)) 15 | self.__ganIndex = (self.__lunar.getDayGanIndexExact() % 5 * 2 + self.__zhiIndex) % 10 16 | 17 | @staticmethod 18 | def fromYmdHms(lunar_year, lunar_month, lunar_day, hour, minute, second): 19 | return LunarTime(lunar_year, lunar_month, lunar_day, hour, minute, second) 20 | 21 | def getGan(self): 22 | return LunarUtil.GAN[self.__ganIndex + 1] 23 | 24 | def getZhi(self): 25 | return LunarUtil.ZHI[self.__zhiIndex + 1] 26 | 27 | def getGanZhi(self): 28 | return "%s%s" % (self.getGan(), self.getZhi()) 29 | 30 | def getShengXiao(self): 31 | return LunarUtil.SHENGXIAO[self.__zhiIndex + 1] 32 | 33 | def getPositionXi(self): 34 | return LunarUtil.POSITION_XI[self.__ganIndex + 1] 35 | 36 | def getPositionXiDesc(self): 37 | return LunarUtil.POSITION_DESC[self.getPositionXi()] 38 | 39 | def getPositionYangGui(self): 40 | return LunarUtil.POSITION_YANG_GUI[self.__ganIndex + 1] 41 | 42 | def getPositionYangGuiDesc(self): 43 | return LunarUtil.POSITION_DESC[self.getPositionYangGui()] 44 | 45 | def getPositionYinGui(self): 46 | return LunarUtil.POSITION_YIN_GUI[self.__ganIndex + 1] 47 | 48 | def getPositionYinGuiDesc(self): 49 | return LunarUtil.POSITION_DESC[self.getPositionYinGui()] 50 | 51 | def getPositionFu(self, sect=2): 52 | return (LunarUtil.POSITION_FU if 1 == sect else LunarUtil.POSITION_FU_2)[self.__ganIndex + 1] 53 | 54 | def getPositionFuDesc(self, sect=2): 55 | return LunarUtil.POSITION_DESC[self.getPositionFu(sect)] 56 | 57 | def getPositionCai(self): 58 | return LunarUtil.POSITION_CAI[self.__ganIndex + 1] 59 | 60 | def getPositionCaiDesc(self): 61 | return LunarUtil.POSITION_DESC[self.getPositionCai()] 62 | 63 | def getChong(self): 64 | return LunarUtil.CHONG[self.__zhiIndex] 65 | 66 | def getChongGan(self): 67 | return LunarUtil.CHONG_GAN[self.__ganIndex] 68 | 69 | def getChongGanTie(self): 70 | return LunarUtil.CHONG_GAN_TIE[self.__ganIndex] 71 | 72 | def getChongShengXiao(self): 73 | chong = self.getChong() 74 | for i in range(0, len(LunarUtil.ZHI)): 75 | if LunarUtil.ZHI[i] == chong: 76 | return LunarUtil.SHENGXIAO[i] 77 | return "" 78 | 79 | def getChongDesc(self): 80 | return "(" + self.getChongGan() + self.getChong() + ")" + self.getChongShengXiao() 81 | 82 | def getSha(self): 83 | return LunarUtil.SHA[self.getZhi()] 84 | 85 | def getNaYin(self): 86 | return LunarUtil.NAYIN[self.getGanZhi()] 87 | 88 | def getTianShen(self): 89 | return LunarUtil.TIAN_SHEN[(self.__zhiIndex + LunarUtil.ZHI_TIAN_SHEN_OFFSET[self.__lunar.getDayZhiExact()]) % 12 + 1] 90 | 91 | def getTianShenType(self): 92 | return LunarUtil.TIAN_SHEN_TYPE[self.getTianShen()] 93 | 94 | def getTianShenLuck(self): 95 | return LunarUtil.TIAN_SHEN_TYPE_LUCK[self.getTianShenType()] 96 | 97 | def getYi(self): 98 | """ 99 | 获取时宜 100 | :return: 宜 101 | """ 102 | return LunarUtil.getTimeYi(self.__lunar.getDayInGanZhiExact(), self.getGanZhi()) 103 | 104 | def getJi(self): 105 | """ 106 | 获取时忌 107 | :return: 忌 108 | """ 109 | return LunarUtil.getTimeJi(self.__lunar.getDayInGanZhiExact(), self.getGanZhi()) 110 | 111 | def getNineStar(self): 112 | solar_ymd = self.__lunar.getSolar().toYmd() 113 | jie_qi = self.__lunar.getJieQiTable() 114 | asc = False 115 | if jie_qi["冬至"] <= solar_ymd < jie_qi["夏至"]: 116 | asc = True 117 | start = 7 if asc else 3 118 | day_zhi = self.__lunar.getDayZhi() 119 | if day_zhi in "子午卯酉": 120 | start = 1 if asc else 9 121 | elif day_zhi in "辰戌丑未": 122 | start = 4 if asc else 6 123 | index = start + self.__zhiIndex - 1 if asc else start - self.__zhiIndex - 1 124 | 125 | if index > 8: 126 | index -= 9 127 | if index < 0: 128 | index += 9 129 | return NineStar.fromIndex(index) 130 | 131 | def getGanIndex(self): 132 | return self.__ganIndex 133 | 134 | def getZhiIndex(self): 135 | return self.__zhiIndex 136 | 137 | def __str__(self): 138 | return self.toString() 139 | 140 | def toString(self): 141 | return self.getGanZhi() 142 | 143 | def getXun(self): 144 | """ 145 | 获取时辰所在旬 146 | :return: 旬 147 | """ 148 | return LunarUtil.getXun(self.getGanZhi()) 149 | 150 | def getXunKong(self): 151 | """ 152 | 获取值时空亡 153 | :return: 空亡(旬空) 154 | """ 155 | return LunarUtil.getXunKong(self.getGanZhi()) 156 | 157 | def getMinHm(self): 158 | hour = self.__lunar.getHour() 159 | if hour < 1: 160 | return "00:00" 161 | elif hour > 22: 162 | return "23:00" 163 | return "%02d:00" % (hour - 1 if hour % 2 == 0 else hour) 164 | 165 | def getMaxHm(self): 166 | hour = self.__lunar.getHour() 167 | if hour < 1: 168 | return "00:59" 169 | elif hour > 22: 170 | return "23:59" 171 | return "%02d:59" % (hour + 1 if hour % 2 != 0 else hour) 172 | -------------------------------------------------------------------------------- /lunar_python/LunarYear.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import threading 3 | from math import floor 4 | from . import Solar, NineStar 5 | from .util import ShouXingUtil, LunarUtil 6 | 7 | 8 | class LunarYear: 9 | """ 10 | 农历年 11 | """ 12 | 13 | YUAN = ("下", "上", "中") 14 | 15 | YUN = ("七", "八", "九", "一", "二", "三", "四", "五", "六") 16 | 17 | __LEAP_11 = (75, 94, 170, 265, 322, 398, 469, 553, 583, 610, 678, 735, 754, 773, 849, 887, 936, 1050, 1069, 1126, 1145, 1164, 1183, 1259, 1278, 1308, 1373, 1403, 1441, 1460, 1498, 1555, 1593, 1612, 1631, 1642, 2033, 2128, 2147, 2242, 2614, 2728, 2910, 3062, 3244, 3339, 3616, 3711, 3730, 3825, 4007, 4159, 4197, 4322, 4341, 4379, 4417, 4531, 4599, 4694, 4713, 4789, 4808, 4971, 5085, 5104, 5161, 5180, 5199, 5294, 5305, 5476, 5677, 5696, 5772, 5791, 5848, 5886, 6049, 6068, 6144, 6163, 6258, 6402, 6440, 6497, 6516, 6630, 6641, 6660, 6679, 6736, 6774, 6850, 6869, 6899, 6918, 6994, 7013, 7032, 7051, 7070, 7089, 7108, 7127, 7146, 7222, 7271, 7290, 7309, 7366, 7385, 7404, 7442, 7461, 7480, 7491, 7499, 7594, 7624, 7643, 7662, 7681, 7719, 7738, 7814, 7863, 7882, 7901, 7939, 7958, 7977, 7996, 18 | 8034, 8053, 8072, 8091, 8121, 8159, 8186, 8216, 8235, 8254, 8273, 8311, 8330, 8341, 8349, 8368, 8444, 8463, 8474, 8493, 8531, 8569, 8588, 8626, 8664, 8683, 8694, 8702, 8713, 8721, 8751, 8789, 8808, 8816, 8827, 8846, 8884, 8903, 8922, 8941, 8971, 9036, 9066, 9085, 9104, 9123, 9142, 9161, 9180, 9199, 9218, 9256, 9294, 9313, 9324, 9343, 9362, 9381, 9419, 9438, 9476, 9514, 9533, 9544, 9552, 9563, 9571, 9582, 9601, 9639, 9658, 9666, 9677, 9696, 9734, 9753, 9772, 9791, 9802, 9821, 9886, 9897, 9916, 9935, 9954, 9973, 9992) 19 | 20 | __LEAP_12 = (37, 56, 113, 132, 151, 189, 208, 227, 246, 284, 303, 341, 360, 379, 417, 436, 458, 477, 496, 515, 534, 572, 591, 629, 648, 667, 697, 716, 792, 811, 830, 868, 906, 925, 944, 963, 982, 1001, 1020, 1039, 1058, 1088, 1153, 1202, 1221, 1240, 1297, 1335, 1392, 1411, 1422, 1430, 1517, 1525, 1536, 1574, 3358, 3472, 3806, 3988, 4751, 4941, 5066, 5123, 5275, 5343, 5438, 5457, 5495, 5533, 5552, 5715, 5810, 5829, 5905, 5924, 6421, 6535, 6793, 6812, 6888, 6907, 7002, 7184, 7260, 7279, 7374, 7556, 7746, 7757, 7776, 7833, 7852, 7871, 7966, 8015, 8110, 8129, 8148, 8224, 8243, 8338, 8406, 8425, 8482, 8501, 8520, 8558, 8596, 8607, 8615, 8645, 8740, 8778, 8835, 8865, 8930, 8960, 8979, 8998, 9017, 9055, 9074, 9093, 9112, 9150, 9188, 9237, 9275, 9332, 9351, 9370, 9408, 9427, 9446, 9457, 9465, 21 | 9495, 9560, 9590, 9628, 9647, 9685, 9715, 9742, 9780, 9810, 9818, 9829, 9848, 9867, 9905, 9924, 9943, 9962, 10000) 22 | 23 | __CACHE_YEAR = None 24 | 25 | __lock = threading.Lock() 26 | 27 | def __init__(self, lunar_year): 28 | self.__year = lunar_year 29 | offset = lunar_year - 4 30 | year_gan_index = offset % 10 31 | year_zhi_index = offset % 12 32 | if year_gan_index < 0: 33 | year_gan_index += 10 34 | if year_zhi_index < 0: 35 | year_zhi_index += 12 36 | self.__ganIndex = year_gan_index 37 | self.__zhiIndex = year_zhi_index 38 | self.__months = [] 39 | self.__jieQiJulianDays = [] 40 | self.compute() 41 | 42 | @staticmethod 43 | def fromYear(lunar_year): 44 | LunarYear.__lock.acquire() 45 | if LunarYear.__CACHE_YEAR is None or LunarYear.__CACHE_YEAR.getYear() != lunar_year: 46 | y = LunarYear(lunar_year) 47 | LunarYear.__CACHE_YEAR = y 48 | else: 49 | y = LunarYear.__CACHE_YEAR 50 | LunarYear.__lock.release() 51 | return y 52 | 53 | def compute(self): 54 | from . import Lunar, Solar, LunarMonth 55 | # 节气 56 | jq = [] 57 | # 合朔,即每月初一 58 | hs = [] 59 | # 每月天数,长度15 60 | day_counts = [] 61 | # 月份 62 | months = [] 63 | 64 | current_year = self.__year 65 | jd = floor((current_year - 2000) * 365.2422 + 180) 66 | # 355是2000.12冬至,得到较靠近jd的冬至估计值 67 | w = floor((jd - 355 + 183) / 365.2422) * 365.2422 + 355 68 | if ShouXingUtil.calcQi(w) > jd: 69 | w -= 365.2422 70 | # 25个节气时刻(北京时间),从冬至开始到下一个冬至以后 71 | for i in range(0, 26): 72 | jq.append(ShouXingUtil.calcQi(w + 15.2184 * i)) 73 | 74 | # 从上年的大雪到下年的立春 精确的节气 75 | for i in range(0, len(Lunar.JIE_QI_IN_USE)): 76 | if i == 0: 77 | jd = ShouXingUtil.qiAccurate2(jq[0] - 15.2184) 78 | elif i <= 26: 79 | jd = ShouXingUtil.qiAccurate2(jq[i - 1]) 80 | else: 81 | jd = ShouXingUtil.qiAccurate2(jq[25] + 15.2184 * (i - 26)) 82 | self.__jieQiJulianDays.append(jd + Solar.J2000) 83 | 84 | # 冬至前的初一,今年"首朔"的日月黄经差w 85 | w = ShouXingUtil.calcShuo(jq[0]) 86 | if w > jq[0]: 87 | w -= 29.53 88 | # 递推每月初一 89 | for i in range(0, 16): 90 | hs.append(ShouXingUtil.calcShuo(w + 29.5306 * i)) 91 | # 每月 92 | for i in range(0, 15): 93 | day_counts.append(int(hs[i + 1] - hs[i])) 94 | months.append(i) 95 | 96 | prev_year = current_year - 1 97 | leap_index = 16 98 | 99 | if current_year in LunarYear.__LEAP_11: 100 | leap_index = 13 101 | elif current_year in LunarYear.__LEAP_12: 102 | leap_index = 14 103 | elif hs[13] <= jq[24]: 104 | i = 1 105 | while hs[i + 1] > jq[2 * i] and i < 13: 106 | i += 1 107 | leap_index = i 108 | for j in range(leap_index, 15): 109 | months[j] -= 1 110 | ymc = [11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 111 | 112 | fm = -1 113 | index = -1 114 | y = prev_year 115 | for i in range(0, 15): 116 | dm = hs[i] + Solar.J2000 117 | v2 = months[i] 118 | mc = ymc[v2 % 12] 119 | if 1724360 <= dm < 1729794: 120 | mc = ymc[(v2 + 1) % 12] 121 | elif 1807724 <= dm < 1808699: 122 | mc = ymc[(v2 + 1) % 12] 123 | elif dm == 1729794 or dm == 1808699: 124 | mc = 12 125 | if fm == -1: 126 | fm = mc 127 | index = mc 128 | if mc < fm: 129 | y += 1 130 | index = 1 131 | fm = mc 132 | if i == leap_index: 133 | mc = -mc 134 | elif dm == 1729794 or dm == 1808699: 135 | mc = -11 136 | self.__months.append(LunarMonth(y, mc, day_counts[i], dm, index)) 137 | index += 1 138 | 139 | def getYear(self): 140 | return self.__year 141 | 142 | def getGanIndex(self): 143 | return self.__ganIndex 144 | 145 | def getZhiIndex(self): 146 | return self.__zhiIndex 147 | 148 | def getGan(self): 149 | return LunarUtil.GAN[self.__ganIndex + 1] 150 | 151 | def getZhi(self): 152 | return LunarUtil.ZHI[self.__zhiIndex + 1] 153 | 154 | def getGanZhi(self): 155 | return "%s%s" % (self.getGan(), self.getZhi()) 156 | 157 | def toString(self): 158 | return str(self.__year) + "" 159 | 160 | def toFullString(self): 161 | return "%d年" % self.__year 162 | 163 | def __str__(self): 164 | return self.toString() 165 | 166 | def getDayCount(self): 167 | n = 0 168 | for m in self.__months: 169 | if m.getYear() == self.__year: 170 | n += m.getDayCount() 171 | return n 172 | 173 | def getMonthsInYear(self): 174 | months = [] 175 | for m in self.__months: 176 | if m.getYear() == self.__year: 177 | months.append(m) 178 | return months 179 | 180 | def getMonths(self): 181 | return self.__months 182 | 183 | def getJieQiJulianDays(self): 184 | return self.__jieQiJulianDays 185 | 186 | def getLeapMonth(self): 187 | """ 188 | 获取闰月 189 | :return: 闰月数字,1代表闰1月,0代表无闰月 190 | """ 191 | for m in self.__months: 192 | if m.getYear() == self.__year and m.isLeap(): 193 | return abs(m.getMonth()) 194 | return 0 195 | 196 | def getMonth(self, lunar_month): 197 | """ 198 | 获取农历月 199 | :param lunar_month: 闰月数字,1代表闰1月,0代表无闰月 200 | :return: 农历月 201 | """ 202 | for m in self.__months: 203 | if m.getYear() == self.__year and m.getMonth() == lunar_month: 204 | return m 205 | return None 206 | 207 | def __getZaoByGan(self, index, name): 208 | offset = index - Solar.fromJulianDay(self.getMonth(1).getFirstJulianDay()).getLunar().getDayGanIndex() 209 | if offset < 0: 210 | offset += 10 211 | return name.replace("几", LunarUtil.NUMBER[offset + 1], 1) 212 | 213 | def __getZaoByZhi(self, index, name): 214 | offset = index - Solar.fromJulianDay(self.getMonth(1).getFirstJulianDay()).getLunar().getDayZhiIndex() 215 | if offset < 0: 216 | offset += 12 217 | return name.replace("几", LunarUtil.NUMBER[offset + 1], 1) 218 | 219 | def getTouLiang(self): 220 | return self.__getZaoByZhi(0, "几鼠偷粮") 221 | 222 | def getCaoZi(self): 223 | return self.__getZaoByZhi(0, "草子几分") 224 | 225 | def getGengTian(self): 226 | """ 227 | 获取耕田(正月第一个丑日是初几,就是几牛耕田) 228 | :return: 耕田,如:六牛耕田 229 | """ 230 | return self.__getZaoByZhi(1, "几牛耕田") 231 | 232 | def getHuaShou(self): 233 | return self.__getZaoByZhi(3, "花收几分") 234 | 235 | def getZhiShui(self): 236 | """ 237 | 获取治水(正月第一个辰日是初几,就是几龙治水) 238 | :return: 治水,如:二龙治水 239 | """ 240 | return self.__getZaoByZhi(4, "几龙治水") 241 | 242 | def getTuoGu(self): 243 | return self.__getZaoByZhi(6, "几马驮谷") 244 | 245 | def getQiangMi(self): 246 | return self.__getZaoByZhi(9, "几鸡抢米") 247 | 248 | def getKanCan(self): 249 | return self.__getZaoByZhi(9, "几姑看蚕") 250 | 251 | def getGongZhu(self): 252 | return self.__getZaoByZhi(11, "几屠共猪") 253 | 254 | def getJiaTian(self): 255 | return self.__getZaoByGan(0, "甲田几分") 256 | 257 | def getFenBing(self): 258 | """ 259 | 获取分饼(正月第一个丙日是初几,就是几人分饼) 260 | :return: 分饼,如:六人分饼 261 | """ 262 | return self.__getZaoByGan(2, "几人分饼") 263 | 264 | def getDeJin(self): 265 | """ 266 | 获取得金(正月第一个辛日是初几,就是几日得金) 267 | :return: 得金,如:一日得金 268 | """ 269 | return self.__getZaoByGan(7, "几日得金") 270 | 271 | def getRenBing(self): 272 | return self.__getZaoByGan(2, self.__getZaoByZhi(2, "几人几丙")) 273 | 274 | def getRenChu(self): 275 | return self.__getZaoByGan(3, self.__getZaoByZhi(2, "几人几锄")) 276 | 277 | def getYuan(self): 278 | return LunarYear.YUAN[int((self.__year + 2696) / 60) % 3] + "元" 279 | 280 | def getYun(self): 281 | return LunarYear.YUN[int((self.__year + 2696) / 20) % 9] + "运" 282 | 283 | def getNineStar(self): 284 | index = LunarUtil.getJiaZiIndex(self.getGanZhi()) + 1 285 | yuan = int((self.__year + 2696) / 60) % 3 286 | offset = (62 + yuan * 3 - index) % 9 287 | if 0 == offset: 288 | offset = 9 289 | return NineStar.fromIndex(offset - 1) 290 | 291 | def getPositionXi(self): 292 | return LunarUtil.POSITION_XI[self.__ganIndex + 1] 293 | 294 | def getPositionXiDesc(self): 295 | return LunarUtil.POSITION_DESC[self.getPositionXi()] 296 | 297 | def getPositionYangGui(self): 298 | return LunarUtil.POSITION_YANG_GUI[self.__ganIndex + 1] 299 | 300 | def getPositionYangGuiDesc(self): 301 | return LunarUtil.POSITION_DESC[self.getPositionYangGui()] 302 | 303 | def getPositionYinGui(self): 304 | return LunarUtil.POSITION_YIN_GUI[self.__ganIndex + 1] 305 | 306 | def getPositionYinGuiDesc(self): 307 | return LunarUtil.POSITION_DESC[self.getPositionYinGui()] 308 | 309 | def getPositionFu(self, sect=2): 310 | return (LunarUtil.POSITION_FU if 1 == sect else LunarUtil.POSITION_FU_2)[self.__ganIndex + 1] 311 | 312 | def getPositionFuDesc(self, sect=2): 313 | return LunarUtil.POSITION_DESC[self.getPositionFu(sect)] 314 | 315 | def getPositionCai(self): 316 | return LunarUtil.POSITION_CAI[self.__ganIndex + 1] 317 | 318 | def getPositionCaiDesc(self): 319 | return LunarUtil.POSITION_DESC[self.getPositionCai()] 320 | 321 | def getPositionTaiSui(self): 322 | return LunarUtil.POSITION_TAI_SUI_YEAR[self.__zhiIndex] 323 | 324 | def getPositionTaiSuiDesc(self): 325 | return LunarUtil.POSITION_DESC[self.getPositionTaiSui()] 326 | 327 | def next(self, n): 328 | """ 329 | 获取往后推几年的阴历年,如果要往前推,则年数用负数 330 | :param n: 年数 331 | :return: 阴历年 332 | """ 333 | return LunarYear.fromYear(self.__year + n) 334 | -------------------------------------------------------------------------------- /lunar_python/NineStar.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from .util import LunarUtil 3 | 4 | 5 | class NineStar: 6 | """ 7 | 九星 8 | """ 9 | 10 | NUMBER = ("一", "二", "三", "四", "五", "六", "七", "八", "九") 11 | COLOR = ("白", "黑", "碧", "绿", "黄", "白", "赤", "白", "紫") 12 | WU_XING = ("水", "土", "木", "木", "土", "金", "金", "土", "火") 13 | POSITION = ("坎", "坤", "震", "巽", "中", "乾", "兑", "艮", "离") 14 | NAME_BEI_DOU = ("天枢", "天璇", "天玑", "天权", "玉衡", "开阳", "摇光", "洞明", "隐元") 15 | NAME_XUAN_KONG = ("贪狼", "巨门", "禄存", "文曲", "廉贞", "武曲", "破军", "左辅", "右弼") 16 | NAME_QI_MEN = ("天蓬", "天芮", "天冲", "天辅", "天禽", "天心", "天柱", "天任", "天英") 17 | BA_MEN_QI_MEN = ("休", "死", "伤", "杜", "", "开", "惊", "生", "景") 18 | NAME_TAI_YI = ("太乙", "摄提", "轩辕", "招摇", "天符", "青龙", "咸池", "太阴", "天乙") 19 | TYPE_TAI_YI = ("吉神", "凶神", "安神", "安神", "凶神", "吉神", "凶神", "吉神", "吉神") 20 | SONG_TAI_YI = ("门中太乙明,星官号贪狼,赌彩财喜旺,婚姻大吉昌,出入无阻挡,参谒见贤良,此行三五里,黑衣别阴阳。", "门前见摄提,百事必忧疑,相生犹自可,相克祸必临,死门并相会,老妇哭悲啼,求谋并吉事,尽皆不相宜,只可藏隐遁,若动伤身疾。", "出入会轩辕,凡事必缠牵,相生全不美,相克更忧煎,远行多不利,博彩尽输钱,九天玄女法,句句不虚言。", "招摇号木星,当之事莫行,相克行人阻,阴人口舌迎,梦寐多惊惧,屋响斧自鸣,阴阳消息理,万法弗违情。", "五鬼为天符,当门阴女谋,相克无好事,行路阻中途,走失难寻觅,道逢有尼姑,此星当门值,万事有灾除。", "神光跃青龙,财气喜重重,投入有酒食,赌彩最兴隆,更逢相生旺,休言克破凶,见贵安营寨,万事总吉同。", "吾将为咸池,当之尽不宜,出入多不利,相克有灾情,赌彩全输尽,求财空手回,仙人真妙语,愚人莫与知,动用虚惊退,反复逆风吹。", "坐临太阴星,百祸不相侵,求谋悉成就,知交有觅寻,回风归来路,恐有殃伏起,密语中记取,慎乎莫轻行。", "迎来天乙星,相逢百事兴,运用和合庆,茶酒喜相迎,求谋并嫁娶,好合有天成,祸福如神验,吉凶甚分明。") 21 | LUCK_XUAN_KONG = ("吉", "凶", "凶", "吉", "凶", "吉", "凶", "吉", "吉") 22 | LUCK_QI_MEN = ("大凶", "大凶", "小吉", "大吉", "大吉", "大吉", "小凶", "小吉", "小凶") 23 | YIN_YANG_QI_MEN = ("阳", "阴", "阳", "阳", "阳", "阴", "阴", "阳", "阴") 24 | 25 | def __init__(self, index): 26 | self.__index = index 27 | 28 | @staticmethod 29 | def fromIndex(index): 30 | return NineStar(index) 31 | 32 | def getNumber(self): 33 | return NineStar.NUMBER[self.__index] 34 | 35 | def getColor(self): 36 | return NineStar.COLOR[self.__index] 37 | 38 | def getWuXing(self): 39 | return NineStar.WU_XING[self.__index] 40 | 41 | def getPosition(self): 42 | return NineStar.POSITION[self.__index] 43 | 44 | def getPositionDesc(self): 45 | return LunarUtil.POSITION_DESC[self.getPosition()] 46 | 47 | def getNameInXuanKong(self): 48 | return NineStar.NAME_XUAN_KONG[self.__index] 49 | 50 | def getNameInBeiDou(self): 51 | return NineStar.NAME_BEI_DOU[self.__index] 52 | 53 | def getNameInQiMen(self): 54 | return NineStar.NAME_QI_MEN[self.__index] 55 | 56 | def getNameInTaiYi(self): 57 | return NineStar.NAME_TAI_YI[self.__index] 58 | 59 | def getLuckInQiMen(self): 60 | return NineStar.LUCK_QI_MEN[self.__index] 61 | 62 | def getLuckInXuanKong(self): 63 | return NineStar.LUCK_XUAN_KONG[self.__index] 64 | 65 | def getYinYangInQiMen(self): 66 | return NineStar.YIN_YANG_QI_MEN[self.__index] 67 | 68 | def getTypeInTaiYi(self): 69 | return NineStar.TYPE_TAI_YI[self.__index] 70 | 71 | def getBaMenInQiMen(self): 72 | return NineStar.BA_MEN_QI_MEN[self.__index] 73 | 74 | def getSongInTaiYi(self): 75 | return NineStar.SONG_TAI_YI[self.__index] 76 | 77 | def getIndex(self): 78 | return self.__index 79 | 80 | def __str__(self): 81 | return self.toString() 82 | 83 | def toString(self): 84 | return self.getNumber() + self.getColor() + self.getWuXing() + self.getNameInBeiDou() 85 | 86 | def toFullString(self): 87 | s = self.getNumber() 88 | s += self.getColor() 89 | s += self.getWuXing() 90 | s += " " 91 | s += self.getPosition() 92 | s += "(" 93 | s += self.getPositionDesc() 94 | s += ") " 95 | s += self.getNameInBeiDou() 96 | s += " 玄空[" 97 | s += self.getNameInXuanKong() 98 | s += " " 99 | s += self.getLuckInXuanKong() 100 | s += "] 奇门[" 101 | s += self.getNameInQiMen() 102 | s += " " 103 | s += self.getLuckInQiMen() 104 | if len(self.getBaMenInQiMen()) > 0: 105 | s += " " 106 | s += self.getBaMenInQiMen() 107 | s += "门" 108 | s += " " 109 | s += self.getYinYangInQiMen() 110 | s += "] 太乙[" 111 | s += self.getNameInTaiYi() 112 | s += " " 113 | s += self.getTypeInTaiYi() 114 | s += "]" 115 | return s 116 | -------------------------------------------------------------------------------- /lunar_python/ShuJiu.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class ShuJiu: 5 | """ 6 | 数九 7 | """ 8 | 9 | def __init__(self, name, index): 10 | self.__name = name 11 | self.__index = index 12 | 13 | def getName(self): 14 | return self.__name 15 | 16 | def setName(self, name): 17 | self.__name = name 18 | 19 | def getIndex(self): 20 | return self.__index 21 | 22 | def setIndex(self, index): 23 | self.__index = index 24 | 25 | def __str__(self): 26 | return self.toString() 27 | 28 | def toString(self): 29 | return self.__name 30 | 31 | def toFullString(self): 32 | return "%s第%d天" % (self.__name, self.__index) 33 | -------------------------------------------------------------------------------- /lunar_python/Solar.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from datetime import datetime 3 | from math import ceil 4 | 5 | from .util import SolarUtil, LunarUtil, HolidayUtil 6 | 7 | 8 | class Solar: 9 | """ 10 | 阳历日期 11 | """ 12 | 13 | # 2000年儒略日数(2000-1-1 12:00:00 UTC) 14 | J2000 = 2451545 15 | 16 | def __init__(self, year, month, day, hour, minute, second): 17 | if year == 1582 and month == 10: 18 | if 4 < day < 15: 19 | raise Exception("wrong solar year %d month %d day %d" % (year, month, day)) 20 | if month < 1 or month > 12: 21 | raise Exception("wrong month %d" % month) 22 | if day < 1 or month > 31: 23 | raise Exception("wrong day %d" % day) 24 | if hour < 0 or hour > 23: 25 | raise Exception("wrong hour %d" % hour) 26 | if minute < 0 or minute > 59: 27 | raise Exception("wrong minute %d" % minute) 28 | if second < 0 or second > 59: 29 | raise Exception("wrong second %d" % second) 30 | self.__year = year 31 | self.__month = month 32 | self.__day = day 33 | self.__hour = hour 34 | self.__minute = minute 35 | self.__second = second 36 | 37 | @staticmethod 38 | def fromDate(date): 39 | return Solar(date.year, date.month, date.day, date.hour, date.minute, date.second) 40 | 41 | @staticmethod 42 | def fromJulianDay(julian_day): 43 | d = int(julian_day + 0.5) 44 | f = julian_day + 0.5 - d 45 | if d >= 2299161: 46 | c = int((d - 1867216.25) / 36524.25) 47 | d += 1 + c - int(c / 4) 48 | d += 1524 49 | year = int((d - 122.1) / 365.25) 50 | d -= int(365.25 * year) 51 | month = int(d / 30.601) 52 | d -= int(30.601 * month) 53 | day = d 54 | if month > 13: 55 | month -= 13 56 | year -= 4715 57 | else: 58 | month -= 1 59 | year -= 4716 60 | f *= 24 61 | hour = int(f) 62 | 63 | f -= hour 64 | f *= 60 65 | minute = int(f) 66 | 67 | f -= minute 68 | f *= 60 69 | second = int(round(f)) 70 | if second > 59: 71 | second -= 60 72 | minute += 1 73 | if minute > 59: 74 | minute -= 60 75 | hour += 1 76 | if hour > 23: 77 | hour -= 24 78 | day += 1 79 | return Solar(year, month, day, hour, minute, second) 80 | 81 | @staticmethod 82 | def fromYmdHms(year, month, day, hour, minute, second): 83 | return Solar(year, month, day, hour, minute, second) 84 | 85 | @staticmethod 86 | def fromYmd(year, month, day): 87 | return Solar(year, month, day, 0, 0, 0) 88 | 89 | @staticmethod 90 | def fromBaZi(year_gan_zhi, month_gan_zhi, day_gan_zhi, time_gan_zhi, sect=2, base_year=1900): 91 | from . import Lunar 92 | sect = 1 if 1 == sect else 2 93 | solar_list = [] 94 | # 月地支距寅月的偏移值 95 | m = LunarUtil.find(month_gan_zhi[1:], LunarUtil.ZHI, -1) - 2 96 | if m < 0: 97 | m += 12 98 | # 月天干要一致 99 | if ((LunarUtil.find(year_gan_zhi[:1], LunarUtil.GAN, -1) + 1) * 2 + m) % 10 != LunarUtil.find(month_gan_zhi[:1], LunarUtil.GAN, -1): 100 | return solar_list 101 | # 1年的立春是辛酉,序号57 102 | y = LunarUtil.getJiaZiIndex(year_gan_zhi) - 57 103 | if y < 0: 104 | y += 60 105 | y += 1 106 | # 节令偏移值 107 | m *= 2 108 | # 时辰地支转时刻,子时按零点算 109 | h = LunarUtil.find(time_gan_zhi[1:], LunarUtil.ZHI, -1) * 2 110 | hours = [h] 111 | if 0 == h and 2 == sect: 112 | hours.append(23) 113 | start_year = base_year - 1 114 | 115 | # 结束年 116 | end_year = datetime.now().year 117 | 118 | while y <= end_year: 119 | if y >= start_year: 120 | # 立春为寅月的开始 121 | jie_qi_table = Lunar.fromYmd(y, 1, 1).getJieQiTable() 122 | # 节令推移,年干支和月干支就都匹配上了 123 | solar_time = jie_qi_table[Lunar.JIE_QI_IN_USE[4 + m]] 124 | if solar_time.getYear() >= base_year: 125 | # 日干支和节令干支的偏移值 126 | d = LunarUtil.getJiaZiIndex(day_gan_zhi) - LunarUtil.getJiaZiIndex(solar_time.getLunar().getDayInGanZhiExact2()) 127 | if d < 0: 128 | d += 60 129 | if d > 0: 130 | # 从节令推移天数 131 | solar_time = solar_time.next(d) 132 | for hour in hours: 133 | mi = 0 134 | s = 0 135 | if d == 0 and hour == solar_time.getHour(): 136 | # 如果正好是节令当天,且小时和节令的小时数相等的极端情况,把分钟和秒钟带上 137 | mi = solar_time.getMinute() 138 | s = solar_time.getSecond() 139 | # 验证一下 140 | solar = Solar.fromYmdHms(solar_time.getYear(), solar_time.getMonth(), solar_time.getDay(), hour, mi, s) 141 | lunar = solar.getLunar() 142 | dgz = lunar.getDayInGanZhiExact2() if 2 == sect else lunar.getDayInGanZhiExact() 143 | if lunar.getYearInGanZhiExact() == year_gan_zhi and lunar.getMonthInGanZhiExact() == month_gan_zhi and dgz == day_gan_zhi and lunar.getTimeInGanZhi() == time_gan_zhi: 144 | solar_list.append(solar) 145 | y += 60 146 | return solar_list 147 | 148 | def isLeapYear(self): 149 | """ 150 | 是否闰年 151 | :return: True/False 闰年/非闰年 152 | """ 153 | return SolarUtil.isLeapYear(self.__year) 154 | 155 | def getWeek(self): 156 | """ 157 | 获取星期,0代表周日,1代表周一 158 | :return: 0123456 159 | """ 160 | return (int(self.getJulianDay() + 0.5) + 7000001) % 7 161 | 162 | def getWeekInChinese(self): 163 | """ 164 | 获取星期的中文 165 | :return: 日一二三四五六 166 | """ 167 | return SolarUtil.WEEK[self.getWeek()] 168 | 169 | def getFestivals(self): 170 | """ 171 | 获取节日,有可能一天会有多个节日 172 | :return: 劳动节等 173 | """ 174 | festivals = [] 175 | key = "%d-%d" % (self.__month, self.__day) 176 | if key in SolarUtil.FESTIVAL: 177 | festivals.append(SolarUtil.FESTIVAL[key]) 178 | week = self.getWeek() 179 | key = "%d-%d-%d" % (self.__month, int(ceil(self.__day / 7.0)), week) 180 | if key in SolarUtil.WEEK_FESTIVAL: 181 | festivals.append(SolarUtil.WEEK_FESTIVAL[key]) 182 | if self.__day + 7 > SolarUtil.getDaysOfMonth(self.__year, self.__month): 183 | key = "%d-0-%d" % (self.__month, week) 184 | if key in SolarUtil.WEEK_FESTIVAL: 185 | festivals.append(SolarUtil.WEEK_FESTIVAL[key]) 186 | return festivals 187 | 188 | def getOtherFestivals(self): 189 | """ 190 | 获取非正式的节日,有可能一天会有多个节日 191 | :return: 非正式的节日列表,如中元节 192 | """ 193 | festivals = [] 194 | key = "%d-%d" % (self.__month, self.__day) 195 | if key in SolarUtil.OTHER_FESTIVAL: 196 | for f in SolarUtil.OTHER_FESTIVAL[key]: 197 | festivals.append(f) 198 | return festivals 199 | 200 | def getXingZuo(self): 201 | """ 202 | 获取星座 203 | :return: 星座 204 | """ 205 | index = 11 206 | y = self.__month * 100 + self.__day 207 | if 321 <= y <= 419: 208 | index = 0 209 | elif 420 <= y <= 520: 210 | index = 1 211 | elif 521 <= y <= 621: 212 | index = 2 213 | elif 622 <= y <= 722: 214 | index = 3 215 | elif 723 <= y <= 822: 216 | index = 4 217 | elif 823 <= y <= 922: 218 | index = 5 219 | elif 923 <= y <= 1023: 220 | index = 6 221 | elif 1024 <= y <= 1122: 222 | index = 7 223 | elif 1123 <= y <= 1221: 224 | index = 8 225 | elif y >= 1222 or y <= 119: 226 | index = 9 227 | elif y <= 218: 228 | index = 10 229 | return SolarUtil.XING_ZUO[index] 230 | 231 | def getJulianDay(self): 232 | """ 233 | 获取儒略日 234 | :return: 儒略日 235 | """ 236 | y = self.__year 237 | m = self.__month 238 | d = self.__day + ((self.__second / 60.0 + self.__minute) / 60 + self.__hour) / 24 239 | n = 0 240 | g = False 241 | if y * 372 + m * 31 + int(d) >= 588829: 242 | g = True 243 | if m <= 2: 244 | m += 12 245 | y -= 1 246 | if g: 247 | n = int(y / 100) 248 | n = 2 - n + int(n / 4) 249 | return int(365.25 * (y + 4716)) + int(30.6001 * (m + 1)) + d + n - 1524.5 250 | 251 | def getLunar(self): 252 | """ 253 | 获取农历 254 | :return: 农历 255 | """ 256 | from .Lunar import Lunar 257 | return Lunar.fromSolar(self) 258 | 259 | def nextDay(self, days): 260 | y = self.__year 261 | m = self.__month 262 | d = self.__day 263 | if 1582 == y and 10 == m: 264 | if d > 4: 265 | d -= 10 266 | if days > 0: 267 | d += days 268 | days_in_month = SolarUtil.getDaysOfMonth(y, m) 269 | while d > days_in_month: 270 | d -= days_in_month 271 | m += 1 272 | if m > 12: 273 | m = 1 274 | y += 1 275 | days_in_month = SolarUtil.getDaysOfMonth(y, m) 276 | elif days < 0: 277 | while d + days <= 0: 278 | m -= 1 279 | if m < 1: 280 | m = 12 281 | y -= 1 282 | d += SolarUtil.getDaysOfMonth(y, m) 283 | d += days 284 | if 1582 == y and 10 == m: 285 | if d > 4: 286 | d += 10 287 | return Solar.fromYmdHms(y, m, d, self.__hour, self.__minute, self.__second) 288 | 289 | def next(self, days, only_work_day=False): 290 | """ 291 | 获取往后推几天的阳历日期,如果要往前推,则天数用负数 292 | :param days: 天数 293 | :param only_work_day: 是否仅工作日 294 | :return: 阳历日期 295 | """ 296 | if not only_work_day: 297 | return self.nextDay(days) 298 | solar = Solar.fromYmdHms(self.__year, self.__month, self.__day, self.__hour, self.__minute, self.__second) 299 | if days != 0: 300 | rest = abs(days) 301 | add = 1 302 | if days < 0: 303 | add = -1 304 | while rest > 0: 305 | solar = solar.next(add) 306 | work = True 307 | holiday = HolidayUtil.getHoliday(solar.getYear(), solar.getMonth(), solar.getDay()) 308 | if holiday is None: 309 | week = solar.getWeek() 310 | if 0 == week or 6 == week: 311 | work = False 312 | else: 313 | work = holiday.isWork() 314 | if work: 315 | rest -= 1 316 | return solar 317 | 318 | def getYear(self): 319 | return self.__year 320 | 321 | def getMonth(self): 322 | return self.__month 323 | 324 | def getDay(self): 325 | return self.__day 326 | 327 | def getHour(self): 328 | return self.__hour 329 | 330 | def getMinute(self): 331 | return self.__minute 332 | 333 | def getSecond(self): 334 | return self.__second 335 | 336 | def toYmd(self): 337 | return "%04d-%02d-%02d" % (self.__year, self.__month, self.__day) 338 | 339 | def toYmdHms(self): 340 | return "%s %02d:%02d:%02d" % (self.toYmd(), self.__hour, self.__minute, self.__second) 341 | 342 | def toFullString(self): 343 | s = self.toYmdHms() 344 | if self.isLeapYear(): 345 | s += " 闰年" 346 | s += " 星期" 347 | s += self.getWeekInChinese() 348 | for f in self.getFestivals(): 349 | s += " (" + f + ")" 350 | for f in self.getOtherFestivals(): 351 | s += " (" + f + ")" 352 | s += " " 353 | s += self.getXingZuo() 354 | s += "座" 355 | return s 356 | 357 | def toString(self): 358 | return self.toYmd() 359 | 360 | def __str__(self): 361 | return self.toString() 362 | 363 | def subtract(self, solar): 364 | return SolarUtil.getDaysBetween(solar.getYear(), solar.getMonth(), solar.getDay(), self.__year, self.__month, self.__day) 365 | 366 | def subtractMinute(self, solar): 367 | days = self.subtract(solar) 368 | cm = self.__hour * 60 + self.__minute 369 | sm = solar.getHour() * 60 + solar.getMinute() 370 | m = cm - sm 371 | if m < 0: 372 | m += 1440 373 | days -= 1 374 | m += days * 1440 375 | return m 376 | 377 | def isAfter(self, solar): 378 | if self.__year > solar.getYear(): 379 | return True 380 | if self.__year < solar.getYear(): 381 | return False 382 | if self.__month > solar.getMonth(): 383 | return True 384 | if self.__month < solar.getMonth(): 385 | return False 386 | if self.__day > solar.getDay(): 387 | return True 388 | if self.__day < solar.getDay(): 389 | return False 390 | if self.__hour > solar.getHour(): 391 | return True 392 | if self.__hour < solar.getHour(): 393 | return False 394 | if self.__minute > solar.getMinute(): 395 | return True 396 | if self.__minute < solar.getMinute(): 397 | return False 398 | return self.__second > solar.getSecond() 399 | 400 | def isBefore(self, solar): 401 | if self.__year > solar.getYear(): 402 | return False 403 | if self.__year < solar.getYear(): 404 | return True 405 | if self.__month > solar.getMonth(): 406 | return False 407 | if self.__month < solar.getMonth(): 408 | return True 409 | if self.__day > solar.getDay(): 410 | return False 411 | if self.__day < solar.getDay(): 412 | return True 413 | if self.__hour > solar.getHour(): 414 | return False 415 | if self.__hour < solar.getHour(): 416 | return True 417 | if self.__minute > solar.getMinute(): 418 | return False 419 | if self.__minute < solar.getMinute(): 420 | return True 421 | return self.__second < solar.getSecond() 422 | 423 | def nextYear(self, years): 424 | y = self.__year + years 425 | m = self.__month 426 | d = self.__day 427 | if 1582 == y and 10 == m: 428 | if 4 < d < 15: 429 | d += 10 430 | elif 2 == m: 431 | if d > 28: 432 | if not SolarUtil.isLeapYear(y): 433 | d = 28 434 | return Solar.fromYmdHms(y, m, d, self.__hour, self.__minute, self.__second) 435 | 436 | def nextMonth(self, months): 437 | from . import SolarMonth 438 | month = SolarMonth.fromYm(self.__year, self.__month).next(months) 439 | y = month.getYear() 440 | m = month.getMonth() 441 | d = self.__day 442 | if 1582 == y and 10 == m: 443 | if 4 < d < 15: 444 | d += 10 445 | else: 446 | days = SolarUtil.getDaysOfMonth(y, m) 447 | if d > days: 448 | d = days 449 | return Solar.fromYmdHms(y, m, d, self.__hour, self.__minute, self.__second) 450 | 451 | def nextHour(self, hours): 452 | h = self.__hour + hours 453 | n = 1 454 | if h < 0: 455 | n = -1 456 | hour = abs(h) 457 | days = int(hour / 24) * n 458 | hour = (hour % 24) * n 459 | if hour < 0: 460 | hour += 24 461 | days -= 1 462 | solar = self.next(days) 463 | return Solar.fromYmdHms(solar.getYear(), solar.getMonth(), solar.getDay(), hour, solar.getMinute(), solar.getSecond()) 464 | -------------------------------------------------------------------------------- /lunar_python/SolarHalfYear.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from math import ceil 3 | 4 | from . import SolarMonth 5 | 6 | 7 | class SolarHalfYear: 8 | """ 9 | 阳历半年 10 | """ 11 | 12 | MONTH_COUNT = 6 13 | 14 | def __init__(self, year, month): 15 | self.__year = year 16 | self.__month = month 17 | 18 | @staticmethod 19 | def fromDate(date): 20 | return SolarHalfYear(date.year, date.month) 21 | 22 | @staticmethod 23 | def fromYm(year, month): 24 | return SolarHalfYear(year, month) 25 | 26 | def getYear(self): 27 | return self.__year 28 | 29 | def getMonth(self): 30 | return self.__month 31 | 32 | def toString(self): 33 | return "%d.%d" % (self.__year, self.getIndex()) 34 | 35 | def toFullString(self): 36 | return "%d年%s半年" % (self.__year, ("上" if 1 == self.getIndex() else "下")) 37 | 38 | def __str__(self): 39 | return self.toString() 40 | 41 | def getIndex(self): 42 | """ 43 | 获取当月是第几半年 44 | :return: 半年序号,从1开始 45 | """ 46 | return int(ceil(self.__month * 1.0 / SolarHalfYear.MONTH_COUNT)) 47 | 48 | def getMonths(self): 49 | """ 50 | 获取本半年的阳历月列表 51 | :return: 阳历月列表 52 | """ 53 | months = [] 54 | index = self.getIndex() - 1 55 | for i in range(0, SolarHalfYear.MONTH_COUNT): 56 | months.append(SolarMonth.fromYm(self.__year, SolarHalfYear.MONTH_COUNT * index + i + 1)) 57 | return months 58 | 59 | def next(self, half_years): 60 | """ 61 | 半年推移 62 | :param half_years: 推移的半年数,负数为倒推 63 | :return: 推移后的半年 64 | """ 65 | m = SolarMonth.fromYm(self.__year, self.__month).next(SolarHalfYear.MONTH_COUNT * half_years) 66 | return SolarHalfYear.fromYm(m.getYear(), m.getMonth()) 67 | -------------------------------------------------------------------------------- /lunar_python/SolarMonth.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from . import Solar, SolarWeek 4 | from .util import SolarUtil 5 | 6 | 7 | class SolarMonth: 8 | """ 9 | 阳历月 10 | """ 11 | 12 | def __init__(self, year, month): 13 | self.__year = year 14 | self.__month = month 15 | 16 | @staticmethod 17 | def fromDate(date): 18 | return SolarMonth(date.year, date.month) 19 | 20 | @staticmethod 21 | def fromYm(year: int, month: int): 22 | return SolarMonth(year, month) 23 | 24 | def getYear(self): 25 | return self.__year 26 | 27 | def getMonth(self): 28 | return self.__month 29 | 30 | def toString(self): 31 | return "%d-%d" % (self.__year, self.__month) 32 | 33 | def toFullString(self): 34 | return "%d年%d月" % (self.__year, self.__month) 35 | 36 | def __str__(self): 37 | return self.toString() 38 | 39 | def getDays(self): 40 | """ 41 | 获取本月的阳历日期列表 42 | :return: 阳历日期列表 43 | """ 44 | days = [] 45 | d = Solar.fromYmd(self.__year, self.__month, 1) 46 | days.append(d) 47 | for i in range(1, SolarUtil.getDaysOfMonth(self.__year, self.__month)): 48 | days.append(d.next(i)) 49 | return days 50 | 51 | def getWeeks(self, start): 52 | """ 53 | 获取本月的阳历日期列表 54 | :param start: 星期几作为一周的开始,1234560分别代表星期一至星期天 55 | :return: 阳历日期列表 56 | """ 57 | weeks = [] 58 | week = SolarWeek.fromYmd(self.__year, self.__month, 1, start) 59 | while True: 60 | weeks.append(week) 61 | week = week.next(1, False) 62 | first_day = week.getFirstDay() 63 | if first_day.getYear() > self.__year or first_day.getMonth() > self.__month: 64 | break 65 | return weeks 66 | 67 | def next(self, months): 68 | """ 69 | 获取往后推几个月的阳历月,如果要往前推,则月数用负数 70 | :param months: 月数 71 | :return: 阳历月 72 | """ 73 | n = 1 74 | if months < 0: 75 | n = -1 76 | m = abs(months) 77 | y = self.__year + int(m / 12) * n 78 | m = self.__month + m % 12 * n 79 | if m > 12: 80 | m -= 12 81 | y += 1 82 | elif m < 1: 83 | m += 12 84 | y -= 1 85 | return SolarMonth.fromYm(y, m) 86 | -------------------------------------------------------------------------------- /lunar_python/SolarSeason.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from math import ceil 3 | 4 | from . import SolarMonth 5 | 6 | 7 | class SolarSeason: 8 | """ 9 | 阳历季度 10 | """ 11 | 12 | MONTH_COUNT = 3 13 | 14 | def __init__(self, year, month): 15 | self.__year = year 16 | self.__month = month 17 | 18 | @staticmethod 19 | def fromDate(date): 20 | return SolarSeason(date.year, date.month) 21 | 22 | @staticmethod 23 | def fromYm(year, month): 24 | return SolarSeason(year, month) 25 | 26 | def getYear(self): 27 | return self.__year 28 | 29 | def getMonth(self): 30 | return self.__month 31 | 32 | def toString(self): 33 | return "%d.%d" % (self.__year, self.getIndex()) 34 | 35 | def toFullString(self): 36 | return "%d年%d季度" % (self.__year, self.getIndex()) 37 | 38 | def __str__(self): 39 | return self.toString() 40 | 41 | def getIndex(self): 42 | """ 43 | 获取当月是第几季度 44 | :return: 季度序号,从1开始 45 | """ 46 | return int(ceil(self.__month * 1.0 / SolarSeason.MONTH_COUNT)) 47 | 48 | def getMonths(self): 49 | """ 50 | 获取本季度的阳历月列表 51 | :return: 阳历月列表 52 | """ 53 | months = [] 54 | index = self.getIndex() - 1 55 | for i in range(0, SolarSeason.MONTH_COUNT): 56 | months.append(SolarMonth.fromYm(self.__year, SolarSeason.MONTH_COUNT * index + i + 1)) 57 | return months 58 | 59 | def next(self, seasons): 60 | """ 61 | 季度推移 62 | :param seasons: 推移的季度数,负数为倒推 63 | :return: 推移后的季度 64 | """ 65 | m = SolarMonth.fromYm(self.__year, self.__month).next(SolarSeason.MONTH_COUNT * seasons) 66 | return SolarSeason.fromYm(m.getYear(), m.getMonth()) 67 | -------------------------------------------------------------------------------- /lunar_python/SolarWeek.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from math import ceil 3 | 4 | from . import Solar 5 | from .util import SolarUtil 6 | 7 | 8 | class SolarWeek: 9 | """ 10 | 阳历周 11 | """ 12 | 13 | def __init__(self, year, month, day, start): 14 | """ 15 | 通过年月日初始化 16 | :param year: 年 17 | :param month: 月,1到12 18 | :param day: 日,1到31 19 | :param start: 星期几作为一周的开始,1234560分别代表星期一至星期天 20 | """ 21 | self.__year = year 22 | self.__month = month 23 | self.__day = day 24 | self.__start = start 25 | 26 | @staticmethod 27 | def fromDate(date, start): 28 | return SolarWeek(date.year, date.month, date.day, start) 29 | 30 | @staticmethod 31 | def fromYmd(year, month, day, start): 32 | return SolarWeek(year, month, day, start) 33 | 34 | def getYear(self): 35 | return self.__year 36 | 37 | def getMonth(self): 38 | return self.__month 39 | 40 | def getDay(self): 41 | return self.__day 42 | 43 | def getStart(self): 44 | return self.__start 45 | 46 | def toString(self): 47 | return "%d.%d.%d" % (self.__year, self.__month, self.getIndex()) 48 | 49 | def toFullString(self): 50 | return "%d年%d月第%d周" % (self.__year, self.__month, self.getIndex()) 51 | 52 | def __str__(self): 53 | return self.toString() 54 | 55 | def getIndex(self): 56 | """ 57 | 获取当前日期是在当月第几周 58 | :return: 周序号,从1开始 59 | """ 60 | offset = Solar.fromYmd(self.__year, self.__month, 1).getWeek() - self.__start 61 | if offset < 0: 62 | offset += 7 63 | return int(ceil((self.__day + offset) * 1.0 / 7)) 64 | 65 | def getIndexInYear(self): 66 | """ 67 | 获取当前日期是在当年第几周 68 | :return: 周序号,从1开始 69 | """ 70 | offset = Solar.fromYmd(self.__year, 1, 1).getWeek() - self.__start 71 | if offset < 0: 72 | offset += 7 73 | return int(ceil((SolarUtil.getDaysInYear(self.__year, self.__month, self.__day) + offset) * 1.0 / 7)) 74 | 75 | def getFirstDay(self): 76 | """ 77 | 获取本周第一天的阳历日期(可能跨月) 78 | :return: 本周第一天的阳历日期 79 | """ 80 | solar = Solar.fromYmd(self.__year, self.__month, self.__day) 81 | prev = solar.getWeek() - self.__start 82 | if prev < 0: 83 | prev += 7 84 | return solar.next(-prev) 85 | 86 | def getFirstDayInMonth(self): 87 | """ 88 | 获取本周第一天的阳历日期(仅限当月) 89 | :return: 本周第一天的阳历日期 90 | """ 91 | for day in self.getDays(): 92 | if self.__month == day.getMonth(): 93 | return day 94 | return None 95 | 96 | def getDays(self): 97 | """ 98 | 获取本周的阳历日期列表(可能跨月) 99 | :return: 本周的阳历日期列表 100 | """ 101 | days = [] 102 | first = self.getFirstDay() 103 | days.append(first) 104 | for i in range(1, 7): 105 | days.append(first.next(i)) 106 | return days 107 | 108 | def getDaysInMonth(self): 109 | """ 110 | 获取本周的阳历日期列表(仅限当月) 111 | :return: 本周的阳历日期列表(仅限当月) 112 | """ 113 | days = [] 114 | for day in self.getDays(): 115 | if self.__month == day.getMonth(): 116 | days.append(day) 117 | return days 118 | 119 | def next(self, weeks, separate_month): 120 | """ 121 | 周推移 122 | :param weeks: 推移的周数,负数为倒推 123 | :param separate_month: 是否按月单独计算 124 | :return: 推移后的阳历周 125 | """ 126 | if 0 == weeks: 127 | return SolarWeek.fromYmd(self.__year, self.__month, self.__day, self.__start) 128 | solar = Solar.fromYmd(self.__year, self.__month, self.__day) 129 | if separate_month: 130 | n = weeks 131 | week = SolarWeek.fromYmd(solar.getYear(), solar.getMonth(), solar.getDay(), self.__start) 132 | month = self.__month 133 | plus = n > 0 134 | days = 7 if plus else -7 135 | while 0 != n: 136 | solar = solar.next(days) 137 | week = SolarWeek.fromYmd(solar.getYear(), solar.getMonth(), solar.getDay(), self.__start) 138 | week_month = week.getMonth() 139 | if month != week_month: 140 | index = week.getIndex() 141 | if plus: 142 | if 1 == index: 143 | first_day = week.getFirstDay() 144 | week = SolarWeek.fromYmd(first_day.getYear(), first_day.getMonth(), first_day.getDay(), self.__start) 145 | week_month = week.getMonth() 146 | else: 147 | solar = Solar.fromYmd(week.getYear(), week.getMonth(), 1) 148 | week = SolarWeek.fromYmd(solar.getYear(), solar.getMonth(), solar.getDay(), self.__start) 149 | else: 150 | if SolarUtil.getWeeksOfMonth(week.getYear(), week.getMonth(), self.__start) == index: 151 | last_day = week.getFirstDay().next(6) 152 | week = SolarWeek.fromYmd(last_day.getYear(), last_day.getMonth(), last_day.getDay(), self.__start) 153 | week_month = week.getMonth() 154 | else: 155 | solar = Solar.fromYmd(week.getYear(), week.getMonth(), SolarUtil.getDaysOfMonth(week.getYear(), week.getMonth())) 156 | week = SolarWeek.fromYmd(solar.getYear(), solar.getMonth(), solar.getDay(), self.__start) 157 | month = week_month 158 | n -= 1 if plus else -1 159 | return week 160 | else: 161 | solar = solar.next(weeks * 7) 162 | return SolarWeek.fromYmd(solar.getYear(), solar.getMonth(), solar.getDay(), self.__start) 163 | -------------------------------------------------------------------------------- /lunar_python/SolarYear.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from . import SolarMonth 4 | 5 | 6 | class SolarYear: 7 | """ 8 | 阳历年 9 | """ 10 | 11 | MONTH_COUNT = 12 12 | 13 | def __init__(self, year): 14 | self.__year = year 15 | 16 | @staticmethod 17 | def fromDate(date): 18 | return SolarYear(date.year) 19 | 20 | @staticmethod 21 | def fromYear(year): 22 | return SolarYear(year) 23 | 24 | def getYear(self): 25 | return self.__year 26 | 27 | def toString(self): 28 | return str(self.__year) 29 | 30 | def toFullString(self): 31 | return "%d年" % self.__year 32 | 33 | def __str__(self): 34 | return self.toString() 35 | 36 | def getMonths(self): 37 | """ 38 | 获取本年的阳历月列表 39 | :return: 阳历月列表 40 | """ 41 | months = [] 42 | m = SolarMonth.fromYm(self.__year, 1) 43 | months.append(m) 44 | for i in range(1, SolarYear.MONTH_COUNT): 45 | months.append(m.next(i)) 46 | return months 47 | 48 | def next(self, years): 49 | """ 50 | 获取往后推几年的阳历年,如果要往前推,则月数用负数 51 | :param years: 年数 52 | :return: 阳历年 53 | """ 54 | return SolarYear.fromYear(self.__year + years) 55 | -------------------------------------------------------------------------------- /lunar_python/Tao.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from . import Lunar, TaoFestival 3 | from .util import LunarUtil, TaoUtil 4 | 5 | 6 | class Tao: 7 | """ 8 | 道历 9 | """ 10 | 11 | BIRTH_YEAR = -2697 12 | 13 | def __init__(self, lunar): 14 | self.__lunar = lunar 15 | 16 | @staticmethod 17 | def fromLunar(lunar): 18 | return Tao(lunar) 19 | 20 | @staticmethod 21 | def fromYmdHms(year, month, day, hour, minute, second): 22 | return Tao.fromLunar(Lunar.fromYmdHms(year + Tao.BIRTH_YEAR, month, day, hour, minute, second)) 23 | 24 | @staticmethod 25 | def fromYmd(year, month, day): 26 | return Tao.fromYmdHms(year, month, day, 0, 0, 0) 27 | 28 | def getLunar(self): 29 | return self.__lunar 30 | 31 | def getYear(self): 32 | return self.__lunar.getYear() - Tao.BIRTH_YEAR 33 | 34 | def getMonth(self): 35 | return self.__lunar.getMonth() 36 | 37 | def getDay(self): 38 | return self.__lunar.getDay() 39 | 40 | def getYearInChinese(self): 41 | y = str(self.getYear()) 42 | s = "" 43 | for i in range(0, len(y)): 44 | s += LunarUtil.NUMBER[ord(y[i]) - 48] 45 | return s 46 | 47 | def getMonthInChinese(self): 48 | return self.__lunar.getMonthInChinese() 49 | 50 | def getDayInChinese(self): 51 | return self.__lunar.getDayInChinese() 52 | 53 | def getFestivals(self): 54 | festivals = [] 55 | md = "%d-%d" % (self.getMonth(), self.getDay()) 56 | if md in TaoUtil.FESTIVAL: 57 | fs = TaoUtil.FESTIVAL[md] 58 | for f in fs: 59 | festivals.append(f) 60 | jq = self.__lunar.getJieQi() 61 | if "冬至" == jq: 62 | festivals.append(TaoFestival("元始天尊圣诞")) 63 | elif "夏至" == jq: 64 | festivals.append(TaoFestival("灵宝天尊圣诞")) 65 | # 八节日 66 | if jq in TaoUtil.BA_JIE: 67 | festivals.append(TaoFestival(TaoUtil.BA_JIE[jq])) 68 | # 八会日 69 | gz = self.__lunar.getDayInGanZhi() 70 | if gz in TaoUtil.BA_HUI: 71 | festivals.append(TaoFestival(TaoUtil.BA_HUI[gz])) 72 | return festivals 73 | 74 | def __isDayIn(self, days): 75 | md = "%d-%d" % (self.getMonth(), self.getDay()) 76 | for d in days: 77 | if md == d: 78 | return True 79 | return False 80 | 81 | def isDaySanHui(self): 82 | return self.__isDayIn(TaoUtil.SAN_HUI) 83 | 84 | def isDaySanYuan(self): 85 | return self.__isDayIn(TaoUtil.SAN_YUAN) 86 | 87 | def isDayBaJie(self): 88 | return self.__lunar.getJieQi() in TaoUtil.BA_JIE 89 | 90 | def isDayWuLa(self): 91 | return self.__isDayIn(TaoUtil.WU_LA) 92 | 93 | def isDayBaHui(self): 94 | return self.__lunar.getDayInGanZhi() in TaoUtil.BA_HUI 95 | 96 | def isDayMingWu(self): 97 | return "戊" == self.__lunar.getDayGan() 98 | 99 | def isDayAnWu(self): 100 | return self.__lunar.getDayZhi() == TaoUtil.AN_WU[abs(self.getMonth()) - 1] 101 | 102 | def isDayWu(self): 103 | return self.isDayMingWu() or self.isDayAnWu() 104 | 105 | def isDayTianShe(self): 106 | ret = False 107 | mz = self.__lunar.getMonthZhi() 108 | dgz = self.__lunar.getDayInGanZhi() 109 | if mz in "寅卯辰": 110 | if "戊寅" == dgz: 111 | ret = True 112 | elif mz in "巳午未": 113 | if "甲午" == dgz: 114 | ret = True 115 | elif mz in "申酉戌": 116 | if "戊申" == dgz: 117 | ret = True 118 | elif mz in "亥子丑": 119 | if "甲子" == dgz: 120 | ret = True 121 | return ret 122 | 123 | def __str__(self): 124 | return self.toString() 125 | 126 | def toString(self): 127 | return "%s年%s月%s" % (self.getYearInChinese(), self.getMonthInChinese(), self.getDayInChinese()) 128 | 129 | def toFullString(self): 130 | return "道歷%s年,天运%s年,%s月,%s日。%s月%s日,%s時。" % (self.getYearInChinese(), self.__lunar.getYearInGanZhi(), self.__lunar.getMonthInGanZhi(), self.__lunar.getDayInGanZhi(), self.getMonthInChinese(), self.getDayInChinese(), self.__lunar.getTimeZhi()) 131 | -------------------------------------------------------------------------------- /lunar_python/TaoFestival.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class TaoFestival: 5 | """ 6 | 道历节日 7 | """ 8 | 9 | def __init__(self, name, remark=None): 10 | self.__name = name 11 | self.__remark = "" if remark is None else remark 12 | 13 | def getName(self): 14 | return self.__name 15 | 16 | def getRemark(self): 17 | return self.__remark 18 | 19 | def __str__(self): 20 | return self.toString() 21 | 22 | def toString(self): 23 | return self.__name 24 | 25 | def toFullString(self): 26 | s = self.__name 27 | if self.__remark is not None and len(self.__remark) > 0: 28 | s += "[" + self.__remark + "]" 29 | return s 30 | -------------------------------------------------------------------------------- /lunar_python/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from .JieQi import JieQi 3 | from .NineStar import NineStar 4 | from .EightChar import EightChar 5 | from .ShuJiu import ShuJiu 6 | from .Fu import Fu 7 | from .Solar import Solar 8 | from .SolarWeek import SolarWeek 9 | from .SolarMonth import SolarMonth 10 | from .SolarSeason import SolarSeason 11 | from .SolarHalfYear import SolarHalfYear 12 | from .SolarYear import SolarYear 13 | from .LunarTime import LunarTime 14 | from .Lunar import Lunar 15 | from .LunarYear import LunarYear 16 | from .LunarMonth import LunarMonth 17 | from .Holiday import Holiday 18 | from .FotoFestival import FotoFestival 19 | from .Foto import Foto 20 | from .TaoFestival import TaoFestival 21 | from .Tao import Tao 22 | -------------------------------------------------------------------------------- /lunar_python/eightchar/DaYun.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from . import XiaoYun, LiuNian 3 | from ..util import LunarUtil 4 | 5 | 6 | class DaYun: 7 | """ 8 | 大运 9 | """ 10 | 11 | def __init__(self, yun, index: int): 12 | self.__yun = yun 13 | self.__lunar = yun.getLunar() 14 | self.__index = index 15 | birth_year = yun.getLunar().getSolar().getYear() 16 | year = yun.getStartSolar().getYear() 17 | if index < 1: 18 | self.__startYear = birth_year 19 | self.__startAge = 1 20 | self.__endYear = year - 1 21 | self.__endAge = year - birth_year 22 | else: 23 | add = (index - 1) * 10 24 | self.__startYear = year + add 25 | self.__startAge = self.__startYear - birth_year + 1 26 | self.__endYear = self.__startYear + 9 27 | self.__endAge = self.__startAge + 9 28 | 29 | def getStartYear(self): 30 | return self.__startYear 31 | 32 | def getEndYear(self): 33 | return self.__endYear 34 | 35 | def getStartAge(self): 36 | return self.__startAge 37 | 38 | def getEndAge(self): 39 | return self.__endAge 40 | 41 | def getIndex(self): 42 | return self.__index 43 | 44 | def getLunar(self): 45 | return self.__lunar 46 | 47 | def getGanZhi(self): 48 | """ 49 | 获取干支 50 | :return: 干支 51 | """ 52 | if self.__index < 1: 53 | return "" 54 | offset = LunarUtil.getJiaZiIndex(self.__lunar.getMonthInGanZhiExact()) 55 | offset += self.__index if self.__yun.isForward() else -self.__index 56 | size = len(LunarUtil.JIA_ZI) 57 | if offset >= size: 58 | offset -= size 59 | if offset < 0: 60 | offset += size 61 | return LunarUtil.JIA_ZI[offset] 62 | 63 | def getXun(self): 64 | """ 65 | 获取所在旬 66 | :return: 旬 67 | """ 68 | return LunarUtil.getXun(self.getGanZhi()) 69 | 70 | def getXunKong(self): 71 | """ 72 | 获取旬空(空亡) 73 | :return: 旬空(空亡) 74 | """ 75 | return LunarUtil.getXunKong(self.getGanZhi()) 76 | 77 | def getLiuNian(self, n=10): 78 | """ 79 | 获取流年 80 | :param n: 轮数 81 | :return: 流年 82 | """ 83 | if self.__index < 1: 84 | n = self.__endYear - self.__startYear + 1 85 | liu_nian = [] 86 | for i in range(0, n): 87 | liu_nian.append(LiuNian(self, i)) 88 | return liu_nian 89 | 90 | def getXiaoYun(self, n=10): 91 | """ 92 | 获取小运 93 | :param n: 轮数 94 | :return: 小运 95 | """ 96 | if self.__index < 1: 97 | n = self.__endYear - self.__startYear + 1 98 | xiao_yun = [] 99 | for i in range(0, n): 100 | xiao_yun.append(XiaoYun(self, i, self.__yun.isForward())) 101 | return xiao_yun 102 | -------------------------------------------------------------------------------- /lunar_python/eightchar/LiuNian.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from . import LiuYue 3 | from ..util import LunarUtil 4 | 5 | 6 | class LiuNian: 7 | """ 8 | 流年 9 | """ 10 | 11 | def __init__(self, da_yun, index): 12 | self.__daYun = da_yun 13 | self.__lunar = da_yun.getLunar() 14 | self.__index = index 15 | self.__year = da_yun.getStartYear() + index 16 | self.__age = da_yun.getStartAge() + index 17 | 18 | def getIndex(self): 19 | return self.__index 20 | 21 | def getYear(self): 22 | return self.__year 23 | 24 | def getAge(self): 25 | return self.__age 26 | 27 | def getGanZhi(self): 28 | """ 29 | 获取干支 30 | :return: 干支 31 | """ 32 | offset = LunarUtil.getJiaZiIndex(self.__lunar.getJieQiTable()["立春"].getLunar().getYearInGanZhiExact()) + self.__index 33 | if self.__daYun.getIndex() > 0: 34 | offset += self.__daYun.getStartAge() - 1 35 | offset %= len(LunarUtil.JIA_ZI) 36 | return LunarUtil.JIA_ZI[offset] 37 | 38 | def getXun(self): 39 | """ 40 | 获取所在旬 41 | :return: 旬 42 | """ 43 | return LunarUtil.getXun(self.getGanZhi()) 44 | 45 | def getXunKong(self): 46 | """ 47 | 获取旬空(空亡) 48 | :return: 旬空(空亡) 49 | """ 50 | return LunarUtil.getXunKong(self.getGanZhi()) 51 | 52 | def getLiuYue(self): 53 | """ 54 | 获取流月 55 | :return: 流月 56 | """ 57 | n = 12 58 | liu_yue = [] 59 | for i in range(0, n): 60 | liu_yue.append(LiuYue(self, i)) 61 | return liu_yue 62 | -------------------------------------------------------------------------------- /lunar_python/eightchar/LiuYue.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from ..util import LunarUtil 4 | 5 | 6 | class LiuYue: 7 | """ 8 | 流月 9 | """ 10 | 11 | def __init__(self, liu_nian, index): 12 | self.__liuNian = liu_nian 13 | self.__index = index 14 | 15 | def getIndex(self): 16 | return self.__index 17 | 18 | def getMonthInChinese(self): 19 | """ 20 | 获取中文的月 21 | :return: 中文月,如正 22 | """ 23 | return LunarUtil.MONTH[self.__index + 1] 24 | 25 | def getGanZhi(self): 26 | """ 27 | 获取干支 28 |29 | 《五虎遁》 30 | 甲己之年丙作首, 31 | 乙庚之年戊为头, 32 | 丙辛之年寻庚上, 33 | 丁壬壬寅顺水流, 34 | 若问戊癸何处走, 35 | 甲寅之上好追求。 36 | :return: 干支 37 | """ 38 | offset = 0 39 | year_gan_zhi = self.__liuNian.getGanZhi() 40 | year_gan = year_gan_zhi[:1] 41 | if "甲" == year_gan or "己" == year_gan: 42 | offset = 2 43 | elif "乙" == year_gan or "庚" == year_gan: 44 | offset = 4 45 | elif "丙" == year_gan or "辛" == year_gan: 46 | offset = 6 47 | elif "丁" == year_gan or "壬" == year_gan: 48 | offset = 8 49 | gan = LunarUtil.GAN[(self.__index + offset) % 10 + 1] 50 | zhi = LunarUtil.ZHI[(self.__index + LunarUtil.BASE_MONTH_ZHI_INDEX) % 12 + 1] 51 | return gan + zhi 52 | 53 | def getXun(self): 54 | """ 55 | 获取所在旬 56 | :return: 旬 57 | """ 58 | return LunarUtil.getXun(self.getGanZhi()) 59 | 60 | def getXunKong(self): 61 | """ 62 | 获取旬空(空亡) 63 | :return: 旬空(空亡) 64 | """ 65 | return LunarUtil.getXunKong(self.getGanZhi()) 66 | -------------------------------------------------------------------------------- /lunar_python/eightchar/XiaoYun.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from ..util import LunarUtil 3 | 4 | 5 | class XiaoYun: 6 | """ 7 | 小运 8 | """ 9 | 10 | def __init__(self, da_yun, index, forward): 11 | self.__daYun = da_yun 12 | self.__lunar = da_yun.getLunar() 13 | self.__index = index 14 | self.__year = da_yun.getStartYear() + index 15 | self.__age = da_yun.getStartAge() + index 16 | self.__forward = forward 17 | 18 | def getIndex(self): 19 | return self.__index 20 | 21 | def getYear(self): 22 | return self.__year 23 | 24 | def getAge(self): 25 | return self.__age 26 | 27 | def getGanZhi(self): 28 | """ 29 | 获取干支 30 | :return: 干支 31 | """ 32 | offset = LunarUtil.getJiaZiIndex(self.__lunar.getTimeInGanZhi()) 33 | add = self.__index + 1 34 | if self.__daYun.getIndex() > 0: 35 | add += self.__daYun.getStartAge() - 1 36 | offset += add if self.__forward else -add 37 | size = len(LunarUtil.JIA_ZI) 38 | while offset < 0: 39 | offset += size 40 | offset %= size 41 | return LunarUtil.JIA_ZI[offset] 42 | 43 | def getXun(self): 44 | """ 45 | 获取所在旬 46 | :return: 旬 47 | """ 48 | return LunarUtil.getXun(self.getGanZhi()) 49 | 50 | def getXunKong(self): 51 | """ 52 | 获取旬空(空亡) 53 | :return: 旬空(空亡) 54 | """ 55 | return LunarUtil.getXunKong(self.getGanZhi()) 56 | -------------------------------------------------------------------------------- /lunar_python/eightchar/Yun.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from . import DaYun 3 | from ..util import LunarUtil 4 | 5 | 6 | class Yun: 7 | """ 8 | 运 9 | """ 10 | 11 | def __init__(self, eight_char, gender, sect=1): 12 | self.__lunar = eight_char.getLunar() 13 | self.__gender = gender 14 | yang = 0 == self.__lunar.getYearGanIndexExact() % 2 15 | man = 1 == gender 16 | self.__forward = (yang and man) or (not yang and not man) 17 | self.__compute_start(sect) 18 | 19 | def __compute_start(self, sect): 20 | """ 21 | 起运计算 22 | """ 23 | prev_jie = self.__lunar.getPrevJie() 24 | next_jie = self.__lunar.getNextJie() 25 | current = self.__lunar.getSolar() 26 | start = current if self.__forward else prev_jie.getSolar() 27 | end = next_jie.getSolar() if self.__forward else current 28 | 29 | hour = 0 30 | 31 | if 2 == sect: 32 | minutes = end.subtractMinute(start) 33 | year = int(minutes / 4320) 34 | minutes -= year * 4320 35 | month = int(minutes / 360) 36 | minutes -= month * 360 37 | day = int(minutes / 12) 38 | minutes -= day * 12 39 | hour = minutes * 2 40 | else: 41 | end_time_zhi_index = 11 if end.getHour() == 23 else LunarUtil.getTimeZhiIndex(end.toYmdHms()[11: 16]) 42 | start_time_zhi_index = 11 if start.getHour() == 23 else LunarUtil.getTimeZhiIndex(start.toYmdHms()[11: 16]) 43 | # 时辰差 44 | hour_diff = end_time_zhi_index - start_time_zhi_index 45 | day_diff = end.subtract(start) 46 | if hour_diff < 0: 47 | hour_diff += 12 48 | day_diff -= 1 49 | month_diff = int(hour_diff * 10 / 30) 50 | month = day_diff * 4 + month_diff 51 | day = hour_diff * 10 - month_diff * 30 52 | year = int(month / 12) 53 | month = month - year * 12 54 | self.__startYear = year 55 | self.__startMonth = month 56 | self.__startDay = day 57 | self.__startHour = hour 58 | 59 | def getGender(self): 60 | """ 61 | 获取性别 62 | :return: 性别(1男 , 0女) 63 | """ 64 | return self.__gender 65 | 66 | def getStartYear(self): 67 | """ 68 | 获取起运年数 69 | :return: 起运年数 70 | """ 71 | return self.__startYear 72 | 73 | def getStartMonth(self): 74 | """ 75 | 获取起运月数 76 | :return: 起运月数 77 | """ 78 | return self.__startMonth 79 | 80 | def getStartDay(self): 81 | """ 82 | 获取起运天数 83 | :return: 起运天数 84 | """ 85 | return self.__startDay 86 | 87 | def getStartHour(self): 88 | """ 89 | 获取起运小时数 90 | :return: 起运小时数 91 | """ 92 | return self.__startHour 93 | 94 | def isForward(self): 95 | """ 96 | 是否顺推 97 | :return: true/false 98 | """ 99 | return self.__forward 100 | 101 | def getLunar(self): 102 | return self.__lunar 103 | 104 | def getStartSolar(self): 105 | """ 106 | 获取起运的阳历日期 107 | :return: 阳历日期 108 | """ 109 | solar = self.__lunar.getSolar() 110 | solar = solar.nextYear(self.__startYear) 111 | solar = solar.nextMonth(self.__startMonth) 112 | solar = solar.next(self.__startDay) 113 | return solar.nextHour(self.__startHour) 114 | 115 | def getDaYun(self, n: int = 10): 116 | """ 117 | 获取大运 118 | :param n: 轮数 119 | :return: 大运 120 | """ 121 | da_yun = [] 122 | for i in range(0, n): 123 | da_yun.append(DaYun(self, i)) 124 | return da_yun 125 | -------------------------------------------------------------------------------- /lunar_python/eightchar/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from .LiuYue import LiuYue 3 | from .LiuNian import LiuNian 4 | from .XiaoYun import XiaoYun 5 | from .DaYun import DaYun 6 | from .Yun import Yun 7 | -------------------------------------------------------------------------------- /lunar_python/util/FotoUtil.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from ..FotoFestival import FotoFestival 3 | 4 | 5 | class FotoUtil: 6 | """ 7 | 佛历工具 8 | """ 9 | 10 | # 观音斋日期 11 | DAY_ZHAI_GUAN_YIN = ("1-8", "2-7", "2-9", "2-19", "3-3", "3-6", "3-13", "4-22", "5-3", "5-17", "6-16", "6-18", "6-19", "6-23", "7-13", "8-16", "9-19", "9-23", "10-2", "11-19", "11-24", "12-25") 12 | 13 | # 27星宿,佛教从印度传入中国,印度把28星宿改为27星宿,把牛宿(牛金牛)纳入了女宿(女土蝠)。 14 | XIU_27 = ("角", "亢", "氐", "房", "心", "尾", "箕", "斗", "女", "虚", "危", "室", "壁", "奎", "娄", "胃", "昴", "毕", "觜", "参", "井", "鬼", "柳", "星", "张", "翼", "轸") 15 | 16 | # 每月初一的27星宿偏移 17 | XIU_OFFSET = (11, 13, 15, 17, 19, 21, 24, 0, 2, 4, 7, 9) 18 | 19 | @staticmethod 20 | def getXiu(month, day): 21 | """ 22 | 获取27星宿 23 | :param month: 佛历月 24 | :param day: 佛历日 25 | :return: 星宿 26 | """ 27 | return FotoUtil.XIU_27[(FotoUtil.XIU_OFFSET[abs(month)-1] + day - 1) % len(FotoUtil.XIU_27)] 28 | 29 | __DJ = "犯者夺纪" 30 | __JS = "犯者减寿" 31 | __SS = "犯者损寿" 32 | __XL = "犯者削禄夺纪" 33 | __JW = "犯者三年内夫妇俱亡" 34 | 35 | __Y = FotoFestival("杨公忌") 36 | __T = FotoFestival("四天王巡行", "", True) 37 | __D = FotoFestival("斗降", __DJ, True) 38 | __S = FotoFestival("月朔", __DJ, True) 39 | __W = FotoFestival("月望", __DJ, True) 40 | __H = FotoFestival("月晦", __JS, True) 41 | __L = FotoFestival("雷斋日", __JS, True) 42 | __J = FotoFestival("九毒日", "犯者夭亡,奇祸不测") 43 | __R = FotoFestival("人神在阴", "犯者得病", True, "宜先一日即戒") 44 | __M = FotoFestival("司命奏事", __JS, True, "如月小,即戒廿九") 45 | __HH = FotoFestival("月晦", __JS, True, "如月小,即戒廿九") 46 | 47 | # 日期对应的非正式节日 48 | FESTIVAL = { 49 | "1-1": [FotoFestival("天腊,玉帝校世人神气禄命", __XL), __S], 50 | "1-3": [FotoFestival("万神都会", __DJ), __D], 51 | "1-5": [FotoFestival("五虚忌")], 52 | "1-6": [FotoFestival("六耗忌"), __L], 53 | "1-7": [FotoFestival("上会日", __SS)], 54 | "1-8": [FotoFestival("五殿阎罗天子诞", __DJ), __T], 55 | "1-9": [FotoFestival("玉皇上帝诞", __DJ)], 56 | "1-13": [__Y], 57 | "1-14": [FotoFestival("三元降", __JS), __T], 58 | "1-15": [FotoFestival("三元降", __JS), FotoFestival("上元神会", __DJ), __W, __T], 59 | "1-16": [FotoFestival("三元降", __JS)], 60 | "1-19": [FotoFestival("长春真人诞")], 61 | "1-23": [FotoFestival("三尸神奏事"), __T], 62 | "1-25": [__H, FotoFestival("天地仓开日", "犯者损寿,子带疾")], 63 | "1-27": [__D], 64 | "1-28": [__R], 65 | "1-29": [__T], 66 | "1-30": [__HH, __M, __T], 67 | "2-1": [FotoFestival("一殿秦广王诞", __DJ), __S], 68 | "2-2": [FotoFestival("万神都会", __DJ), FotoFestival("福德土地正神诞", "犯者得祸")], 69 | "2-3": [FotoFestival("文昌帝君诞", __XL), __D], 70 | "2-6": [FotoFestival("东华帝君诞"), __L], 71 | "2-8": [FotoFestival("释迦牟尼佛出家", __DJ), FotoFestival("三殿宋帝王诞", __DJ), FotoFestival("张大帝诞", __DJ), __T], 72 | "2-11": [__Y], 73 | "2-14": [__T], 74 | "2-15": [FotoFestival("释迦牟尼佛涅槃", __XL), FotoFestival("太上老君诞", __XL), FotoFestival("月望", __XL, True), __T], 75 | "2-17": [FotoFestival("东方杜将军诞")], 76 | "2-18": [FotoFestival("四殿五官王诞", __XL), FotoFestival("至圣先师孔子讳辰", __XL)], 77 | "2-19": [FotoFestival("观音大士诞", __DJ)], 78 | "2-21": [FotoFestival("普贤菩萨诞")], 79 | "2-23": [__T], 80 | "2-25": [__H], 81 | "2-27": [__D], 82 | "2-28": [__R], 83 | "2-29": [__T], 84 | "2-30": [__HH, __M, __T], 85 | "3-1": [FotoFestival("二殿楚江王诞", __DJ), __S], 86 | "3-3": [FotoFestival("玄天上帝诞", __DJ), __D], 87 | "3-6": [__L], 88 | "3-8": [FotoFestival("六殿卞城王诞", __DJ), __T], 89 | "3-9": [FotoFestival("牛鬼神出", "犯者产恶胎"), __Y], 90 | "3-12": [FotoFestival("中央五道诞")], 91 | "3-14": [__T], 92 | "3-15": [FotoFestival("昊天上帝诞", __DJ), FotoFestival("玄坛诞", __DJ), __W, __T], 93 | "3-16": [FotoFestival("准提菩萨诞", __DJ)], 94 | "3-19": [FotoFestival("中岳大帝诞"), FotoFestival("后土娘娘诞"), FotoFestival("三茅降")], 95 | "3-20": [FotoFestival("天地仓开日", __SS), FotoFestival("子孙娘娘诞")], 96 | "3-23": [__T], 97 | "3-25": [__H], 98 | "3-27": [FotoFestival("七殿泰山王诞"), __D], 99 | "3-28": [__R, FotoFestival("苍颉至圣先师诞", __XL), FotoFestival("东岳大帝诞")], 100 | "3-29": [__T], 101 | "3-30": [__HH, __M, __T], 102 | "4-1": [FotoFestival("八殿都市王诞", __DJ), __S], 103 | "4-3": [__D], 104 | "4-4": [FotoFestival("万神善会", "犯者失瘼夭胎"), FotoFestival("文殊菩萨诞")], 105 | "4-6": [__L], 106 | "4-7": [FotoFestival("南斗、北斗、西斗同降", __JS), __Y], 107 | "4-8": [FotoFestival("释迦牟尼佛诞", __DJ), FotoFestival("万神善会", "犯者失瘼夭胎"), FotoFestival("善恶童子降", "犯者血死"), FotoFestival("九殿平等王诞"), __T], 108 | "4-14": [FotoFestival("纯阳祖师诞", __JS), __T], 109 | "4-15": [__W, FotoFestival("钟离祖师诞"), __T], 110 | "4-16": [FotoFestival("天地仓开日", __SS)], 111 | "4-17": [FotoFestival("十殿转轮王诞", __DJ)], 112 | "4-18": [FotoFestival("天地仓开日", __SS), FotoFestival("紫徽大帝诞", __SS)], 113 | "4-20": [FotoFestival("眼光圣母诞")], 114 | "4-23": [__T], 115 | "4-25": [__H], 116 | "4-27": [__D], 117 | "4-28": [__R], 118 | "4-29": [__T], 119 | "4-30": [__HH, __M, __T], 120 | "5-1": [FotoFestival("南极长生大帝诞", __DJ), __S], 121 | "5-3": [__D], 122 | "5-5": [FotoFestival("地腊", __XL), FotoFestival("五帝校定生人官爵", __XL), __J, __Y], 123 | "5-6": [__J, __L], 124 | "5-7": [__J], 125 | "5-8": [FotoFestival("南方五道诞"), __T], 126 | "5-11": [FotoFestival("天地仓开日", __SS), FotoFestival("天下都城隍诞")], 127 | "5-12": [FotoFestival("炳灵公诞")], 128 | "5-13": [FotoFestival("关圣降", __XL)], 129 | "5-14": [FotoFestival("夜子时为天地交泰", __JW), __T], 130 | "5-15": [__W, __J, __T], 131 | "5-16": [FotoFestival("九毒日", __JW), FotoFestival("天地元气造化万物之辰", __JW)], 132 | "5-17": [__J], 133 | "5-18": [FotoFestival("张天师诞")], 134 | "5-22": [FotoFestival("孝娥神诞", __DJ)], 135 | "5-23": [__T], 136 | "5-25": [__J, __H], 137 | "5-26": [__J], 138 | "5-27": [__J, __D], 139 | "5-28": [__R], 140 | "5-29": [__T], 141 | "5-30": [__HH, __M, __T], 142 | "6-1": [__S], 143 | "6-3": [FotoFestival("韦驮菩萨圣诞"), __D, __Y], 144 | "6-5": [FotoFestival("南赡部洲转大轮", __SS)], 145 | "6-6": [FotoFestival("天地仓开日", __SS), __L], 146 | "6-8": [__T], 147 | "6-10": [FotoFestival("金粟如来诞")], 148 | "6-14": [__T], 149 | "6-15": [__W, __T], 150 | "6-19": [FotoFestival("观世音菩萨成道", __DJ)], 151 | "6-23": [FotoFestival("南方火神诞", "犯者遭回禄"), __T], 152 | "6-24": [FotoFestival("雷祖诞", __XL), FotoFestival("关帝诞", __XL)], 153 | "6-25": [__H], 154 | "6-27": [__D], 155 | "6-28": [__R], 156 | "6-29": [__T], 157 | "6-30": [__HH, __M, __T], 158 | "7-1": [__S, __Y], 159 | "7-3": [__D], 160 | "7-5": [FotoFestival("中会日", __SS, False, "一作初七")], 161 | "7-6": [__L], 162 | "7-7": [FotoFestival("道德腊", __XL), FotoFestival("五帝校生人善恶", __XL), FotoFestival("魁星诞", __XL)], 163 | "7-8": [__T], 164 | "7-10": [FotoFestival("阴毒日", "", False, "大忌")], 165 | "7-12": [FotoFestival("长真谭真人诞")], 166 | "7-13": [FotoFestival("大势至菩萨诞", __JS)], 167 | "7-14": [FotoFestival("三元降", __JS), __T], 168 | "7-15": [__W, FotoFestival("三元降", __DJ), FotoFestival("地官校籍", __DJ), __T], 169 | "7-16": [FotoFestival("三元降", __JS)], 170 | "7-18": [FotoFestival("西王母诞", __DJ)], 171 | "7-19": [FotoFestival("太岁诞", __DJ)], 172 | "7-22": [FotoFestival("增福财神诞", __XL)], 173 | "7-23": [__T], 174 | "7-25": [__H], 175 | "7-27": [__D], 176 | "7-28": [__R], 177 | "7-29": [__Y, __T], 178 | "7-30": [FotoFestival("地藏菩萨诞", __DJ), __HH, __M, __T], 179 | "8-1": [__S, FotoFestival("许真君诞")], 180 | "8-3": [__D, FotoFestival("北斗诞", __XL), FotoFestival("司命灶君诞", "犯者遭回禄")], 181 | "8-5": [FotoFestival("雷声大帝诞", __DJ)], 182 | "8-6": [__L], 183 | "8-8": [__T], 184 | "8-10": [FotoFestival("北斗大帝诞")], 185 | "8-12": [FotoFestival("西方五道诞")], 186 | "8-14": [__T], 187 | "8-15": [__W, FotoFestival("太明朝元", "犯者暴亡", False, "宜焚香守夜"), __T], 188 | "8-16": [FotoFestival("天曹掠刷真君降", "犯者贫夭")], 189 | "8-18": [FotoFestival("天人兴福之辰", "", False, "宜斋戒,存想吉事")], 190 | "8-23": [FotoFestival("汉恒候张显王诞"), __T], 191 | "8-24": [FotoFestival("灶君夫人诞")], 192 | "8-25": [__H], 193 | "8-27": [__D, FotoFestival("至圣先师孔子诞", __XL), __Y], 194 | "8-28": [__R, FotoFestival("四天会事")], 195 | "8-29": [__T], 196 | "8-30": [FotoFestival("诸神考校", "犯者夺算"), __HH, __M, __T], 197 | "9-1": [__S, FotoFestival("南斗诞", __XL), FotoFestival("北斗九星降世", __DJ, False, "此九日俱宜斋戒")], 198 | "9-3": [__D, FotoFestival("五瘟神诞")], 199 | "9-6": [__L], 200 | "9-8": [__T], 201 | "9-9": [FotoFestival("斗母诞", __XL), FotoFestival("酆都大帝诞"), FotoFestival("玄天上帝飞升")], 202 | "9-10": [FotoFestival("斗母降", __DJ)], 203 | "9-11": [FotoFestival("宜戒")], 204 | "9-13": [FotoFestival("孟婆尊神诞")], 205 | "9-14": [__T], 206 | "9-15": [__W, __T], 207 | "9-17": [FotoFestival("金龙四大王诞", "犯者遭水厄")], 208 | "9-19": [FotoFestival("日宫月宫会合", __JS), FotoFestival("观世音菩萨诞", __JS)], 209 | "9-23": [__T], 210 | "9-25": [__H, __Y], 211 | "9-27": [__D], 212 | "9-28": [__R], 213 | "9-29": [__T], 214 | "9-30": [FotoFestival("药师琉璃光佛诞", "犯者危疾"), __HH, __M, __T], 215 | "10-1": [__S, FotoFestival("民岁腊", __DJ), FotoFestival("四天王降", "犯者一年内死")], 216 | "10-3": [__D, FotoFestival("三茅诞")], 217 | "10-5": [FotoFestival("下会日", __JS), FotoFestival("达摩祖师诞", __JS)], 218 | "10-6": [__L, FotoFestival("天曹考察", __DJ)], 219 | "10-8": [FotoFestival("佛涅槃日", "", False, "大忌色欲"), __T], 220 | "10-10": [FotoFestival("四天王降", "犯者一年内死")], 221 | "10-11": [FotoFestival("宜戒")], 222 | "10-14": [FotoFestival("三元降", __JS), __T], 223 | "10-15": [__W, FotoFestival("三元降", __DJ), FotoFestival("下元水府校籍", __DJ), __T], 224 | "10-16": [FotoFestival("三元降", __JS), __T], 225 | "10-23": [__Y, __T], 226 | "10-25": [__H], 227 | "10-27": [__D, FotoFestival("北极紫徽大帝降")], 228 | "10-28": [__R], 229 | "10-29": [__T], 230 | "10-30": [__HH, __M, __T], 231 | "11-1": [__S], 232 | "11-3": [__D], 233 | "11-4": [FotoFestival("至圣先师孔子诞", __XL)], 234 | "11-6": [FotoFestival("西岳大帝诞")], 235 | "11-8": [__T], 236 | "11-11": [FotoFestival("天地仓开日", __DJ), FotoFestival("太乙救苦天尊诞", __DJ)], 237 | "11-14": [__T], 238 | "11-15": [FotoFestival("月望", "上半夜犯男死 下半夜犯女死"), FotoFestival("四天王巡行", "上半夜犯男死 下半夜犯女死")], 239 | "11-17": [FotoFestival("阿弥陀佛诞")], 240 | "11-19": [FotoFestival("太阳日宫诞", "犯者得奇祸")], 241 | "11-21": [__Y], 242 | "11-23": [FotoFestival("张仙诞", "犯者绝嗣"), __T], 243 | "11-25": [FotoFestival("掠刷大夫降", "犯者遭大凶"), __H], 244 | "11-26": [FotoFestival("北方五道诞")], 245 | "11-27": [__D], 246 | "11-28": [__R], 247 | "11-29": [__T], 248 | "11-30": [__HH, __M, __T], 249 | "12-1": [__S], 250 | "12-3": [__D], 251 | "12-6": [FotoFestival("天地仓开日", __JS), __L], 252 | "12-7": [FotoFestival("掠刷大夫降", "犯者得恶疾")], 253 | "12-8": [FotoFestival("王侯腊", __DJ), FotoFestival("释迦如来成佛之辰"), __T, FotoFestival("初旬内戊日,亦名王侯腊", __DJ)], 254 | "12-12": [FotoFestival("太素三元君朝真")], 255 | "12-14": [__T], 256 | "12-15": [__W, __T], 257 | "12-16": [FotoFestival("南岳大帝诞")], 258 | "12-19": [__Y], 259 | "12-20": [FotoFestival("天地交道", "犯者促寿")], 260 | "12-21": [FotoFestival("天猷上帝诞")], 261 | "12-23": [FotoFestival("五岳诞降"), __T], 262 | "12-24": [FotoFestival("司今朝天奏人善恶", "犯者得大祸")], 263 | "12-25": [FotoFestival("三清玉帝同降,考察善恶", "犯者得奇祸"), __H], 264 | "12-27": [__D], 265 | "12-28": [__R], 266 | "12-29": [FotoFestival("华严菩萨诞"), __T], 267 | "12-30": [FotoFestival("诸神下降,察访善恶", "犯者男女俱亡")] 268 | } 269 | 270 | OTHER_FESTIVAL = { 271 | "1-1": ["弥勒菩萨圣诞"], 272 | "1-6": ["定光佛圣诞"], 273 | "2-8": ["释迦牟尼佛出家"], 274 | "2-15": ["释迦牟尼佛涅槃"], 275 | "2-19": ["观世音菩萨圣诞"], 276 | "2-21": ["普贤菩萨圣诞"], 277 | "3-16": ["准提菩萨圣诞"], 278 | "4-4": ["文殊菩萨圣诞"], 279 | "4-8": ["释迦牟尼佛圣诞"], 280 | "4-15": ["佛吉祥日"], 281 | "4-28": ["药王菩萨圣诞"], 282 | "5-13": ["伽蓝菩萨圣诞"], 283 | "6-3": ["韦驮菩萨圣诞"], 284 | "6-19": ["观音菩萨成道"], 285 | "7-13": ["大势至菩萨圣诞"], 286 | "7-15": ["佛欢喜日"], 287 | "7-24": ["龙树菩萨圣诞"], 288 | "7-30": ["地藏菩萨圣诞"], 289 | "8-15": ["月光菩萨圣诞"], 290 | "8-22": ["燃灯佛圣诞"], 291 | "9-9": ["摩利支天菩萨圣诞"], 292 | "9-19": ["观世音菩萨出家"], 293 | "9-30": ["药师琉璃光佛圣诞"], 294 | "10-5": ["达摩祖师圣诞"], 295 | "10-20": ["文殊菩萨出家"], 296 | "11-17": ["阿弥陀佛圣诞"], 297 | "11-19": ["日光菩萨圣诞"], 298 | "12-8": ["释迦牟尼佛成道"], 299 | "12-23": ["监斋菩萨圣诞"], 300 | "12-29": ["华严菩萨圣诞"] 301 | } 302 | 303 | def __init__(self): 304 | pass 305 | -------------------------------------------------------------------------------- /lunar_python/util/HolidayUtil.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class HolidayUtil: 5 | """ 6 | 法定节假日工具(自2001年12月29日起) 7 | """ 8 | 9 | __SIZE = 18 10 | __ZERO = 48 11 | __TAG_REMOVE = "~" 12 | NAMES = ("元旦节", "春节", "清明节", "劳动节", "端午节", "中秋节", "国庆节", "国庆中秋", "抗战胜利日") 13 | __DATA = "200112290020020101200112300020020101200201010120020101200201020120020101200201030120020101200202091020020212200202101020020212200202121120020212200202131120020212200202141120020212200202151120020212200202161120020212200202171120020212200202181120020212200204273020020501200204283020020501200205013120020501200205023120020501200205033120020501200205043120020501200205053120020501200205063120020501200205073120020501200209286020021001200209296020021001200210016120021001200210026120021001200210036120021001200210046120021001200210056120021001200210066120021001200210076120021001200301010120030101200302011120030201200302021120030201200302031120030201200302041120030201200302051120030201200302061120030201200302071120030201200302081020030201200302091020030201200304263020030501200304273020030501200305013120030501200305023120030501200305033120030501200305043120030501200305053120030501200305063120030501200305073120030501200309276020031001200309286020031001200310016120031001200310026120031001200310036120031001200310046120031001200310056120031001200310066120031001200310076120031001200401010120040101200401171020040122200401181020040122200401221120040122200401231120040122200401241120040122200401251120040122200401261120040122200401271120040122200401281120040122200405013120040501200405023120040501200405033120040501200405043120040501200405053120040501200405063120040501200405073120040501200405083020040501200405093020040501200410016120041001200410026120041001200410036120041001200410046120041001200410056120041001200410066120041001200410076120041001200410096020041001200410106020041001200501010120050101200501020120050101200501030120050101200502051020050209200502061020050209200502091120050209200502101120050209200502111120050209200502121120050209200502131120050209200502141120050209200502151120050209200504303020050501200505013120050501200505023120050501200505033120050501200505043120050501200505053120050501200505063120050501200505073120050501200505083020050501200510016120051001200510026120051001200510036120051001200510046120051001200510056120051001200510066120051001200510076120051001200510086020051001200510096020051001200512310020060101200601010120060101200601020120060101200601030120060101200601281020060129200601291120060129200601301120060129200601311120060129200602011120060129200602021120060129200602031120060129200602041120060129200602051020060129200604293020060501200604303020060501200605013120060501200605023120060501200605033120060501200605043120060501200605053120060501200605063120060501200605073120060501200609306020061001200610016120061001200610026120061001200610036120061001200610046120061001200610056120061001200610066120061001200610076120061001200610086020061001200612300020070101200612310020070101200701010120070101200701020120070101200701030120070101200702171020070218200702181120070218200702191120070218200702201120070218200702211120070218200702221120070218200702231120070218200702241120070218200702251020070218200704283020070501200704293020070501200705013120070501200705023120070501200705033120070501200705043120070501200705053120070501200705063120070501200705073120070501200709296020071001200709306020071001200710016120071001200710026120071001200710036120071001200710046120071001200710056120071001200710066120071001200710076120071001200712290020080101200712300120080101200712310120080101200801010120080101200802021020080206200802031020080206200802061120080206200802071120080206200802081120080206200802091120080206200802101120080206200802111120080206200802121120080206200804042120080404200804052120080404200804062120080404200805013120080501200805023120080501200805033120080501200805043020080501200806074120080608200806084120080608200806094120080608200809135120080914200809145120080914200809155120080914200809276020081001200809286020081001200809296120081001200809306120081001200810016120081001200810026120081001200810036120081001200810046120081001200810056120081001200901010120090101200901020120090101200901030120090101200901040020090101200901241020090125200901251120090125200901261120090125200901271120090125200901281120090125200901291120090125200901301120090125200901311120090125200902011020090125200904042120090404200904052120090404200904062120090404200905013120090501200905023120090501200905033120090501200905284120090528200905294120090528200905304120090528200905314020090528200909276020091001200910016120091001200910026120091001200910036120091001200910046120091001200910055120091003200910065120091003200910075120091003200910085120091003200910105020091003201001010120100101201001020120100101201001030120100101201002131120100213201002141120100213201002151120100213201002161120100213201002171120100213201002181120100213201002191120100213201002201020100213201002211020100213201004032120100405201004042120100405201004052120100405201005013120100501201005023120100501201005033120100501201006124020100616201006134020100616201006144120100616201006154120100616201006164120100616201009195020100922201009225120100922201009235120100922201009245120100922201009255020100922201009266020101001201010016120101001201010026120101001201010036120101001201010046120101001201010056120101001201010066120101001201010076120101001201010096020101001201101010120110101201101020120110101201101030120110101201101301020110203201102021120110203201102031120110203201102041120110203201102051120110203201102061120110203201102071120110203201102081120110203201102121020110203201104022020110405201104032120110405201104042120110405201104052120110405201104303120110501201105013120110501201105023120110501201106044120110606201106054120110606201106064120110606201109105120110912201109115120110912201109125120110912201110016120111001201110026120111001201110036120111001201110046120111001201110056120111001201110066120111001201110076120111001201110086020111001201110096020111001201112310020120101201201010120120101201201020120120101201201030120120101201201211020120123201201221120120123201201231120120123201201241120120123201201251120120123201201261120120123201201271120120123201201281120120123201201291020120123201203312020120404201204012020120404201204022120120404201204032120120404201204042120120404201204283020120501201204293120120501201204303120120501201205013120120501201205023020120501201206224120120623201206234120120623201206244120120623201209295020120930201209305120120930201210016120121001201210026120121001201210036120121001201210046120121001201210056120121001201210066120121001201210076120121001201210086020121001201301010120130101201301020120130101201301030120130101201301050020130101201301060020130101201302091120130210201302101120130210201302111120130210201302121120130210201302131120130210201302141120130210201302151120130210201302161020130210201302171020130210201304042120130404201304052120130404201304062120130404201304273020130501201304283020130501201304293120130501201304303120130501201305013120130501201306084020130612201306094020130612201306104120130612201306114120130612201306124120130612201309195120130919201309205120130919201309215120130919201309225020130919201309296020131001201310016120131001201310026120131001201310036120131001201310046120131001201310056120131001201310066120131001201310076120131001201401010120140101201401261020140131201401311120140131201402011120140131201402021120140131201402031120140131201402041120140131201402051120140131201402061120140131201402081020140131201404052120140405201404062120140405201404072120140405201405013120140501201405023120140501201405033120140501201405043020140501201405314120140602201406014120140602201406024120140602201409065120140908201409075120140908201409085120140908201409286020141001201410016120141001201410026120141001201410036120141001201410046120141004201410056120141001201410066120141001201410076120141001201410116020141001201501010120150101201501020120150101201501030120150101201501040020150101201502151020150219201502181120150219201502191120150219201502201120150219201502211120150219201502221120150219201502231120150219201502241120150219201502281020150219201504042120150405201504052120150405201504062120150405201505013120150501201505023120150501201505033120150501201506204120150620201506214120150620201506224120150620201509038120150903201509048120150903201509058120150903201509068020150903201509265120150927201509275120150927201510016120151001201510026120151001201510036120151001201510046120151004201510056120151001201510066120151001201510076120151001201510106020151001201601010120160101201601020120160101201601030120160101201602061020160208201602071120160208201602081120160208201602091120160208201602101120160208201602111120160208201602121120160208201602131120160208201602141020160208201604022120160404201604032120160404201604042120160404201604303120160501201605013120160501201605023120160501201606094120160609201606104120160609201606114120160609201606124020160609201609155120160915201609165120160915201609175120160915201609185020160915201610016120161001201610026120161001201610036120161001201610046120161001201610056120161001201610066120161001201610076120161001201610086020161001201610096020161001201612310120170101201701010120170101201701020120170101201701221020170128201701271120170128201701281120170128201701291120170128201701301120170128201701311120170128201702011120170128201702021120170128201702041020170128201704012020170404201704022120170404201704032120170404201704042120170404201704293120170501201704303120170501201705013120170501201705274020170530201705284120170530201705294120170530201705304120170530201709306020171001201710016120171001201710026120171001201710036120171001201710045120171004201710056120171001201710066120171001201710076120171001201710086120171001201712300120180101201712310120180101201801010120180101201802111020180216201802151120180216201802161120180216201802171120180216201802181120180216201802191120180216201802201120180216201802211120180216201802241020180216201804052120180405201804062120180405201804072120180405201804082020180405201804283020180501201804293120180501201804303120180501201805013120180501201806164120180618201806174120180618201806184120180618201809225120180924201809235120180924201809245120180924201809296020181001201809306020181001201810016120181001201810026120181001201810036120181001201810046120181001201810056120181001201810066120181001201810076120181001201812290020190101201812300120190101201812310120190101201901010120190101201902021020190205201902031020190205201902041120190205201902051120190205201902061120190205201902071120190205201902081120190205201902091120190205201902101120190205201904052120190405201904062120190405201904072120190405201904283020190501201905013120190501201905023120190501201905033120190501201905043120190501201905053020190501201906074120190607201906084120190607201906094120190607201909135120190913201909145120190913201909155120190913201909296020191001201910016120191001201910026120191001201910036120191001201910046120191001201910056120191001201910066120191001201910076120191001201910126020191001202001010120200101202001191020200125202001241120200125202001251120200125202001261120200125202001271120200125202001281120200125202001291120200125202001301120200125202001311120200125202002011120200125202002021120200125202004042120200404202004052120200404202004062120200404202004263020200501202005013120200501202005023120200501202005033120200501202005043120200501202005053120200501202005093020200501202006254120200625202006264120200625202006274120200625202006284020200625202009277020201001202010017120201001202010026120201001202010036120201001202010046120201001202010056120201001202010066120201001202010076120201001202010086120201001202010106020201001202101010120210101202101020120210101202101030120210101202102071020210212202102111120210212202102121120210212202102131120210212202102141120210212202102151120210212202102161120210212202102171120210212202102201020210212202104032120210404202104042120210404202104052120210404202104253020210501202105013120210501202105023120210501202105033120210501202105043120210501202105053120210501202105083020210501202106124120210614202106134120210614202106144120210614202109185020210921202109195120210921202109205120210921202109215120210921202109266020211001202110016120211001202110026120211001202110036120211001202110046120211001202110056120211001202110066120211001202110076120211001202110096020211001202201010120220101202201020120220101202201030120220101202201291020220201202201301020220201202201311120220201202202011120220201202202021120220201202202031120220201202202041120220201202202051120220201202202061120220201202204022020220405202204032120220405202204042120220405202204052120220405202204243020220501202204303120220501202205013120220501202205023120220501202205033120220501202205043120220501202205073020220501202206034120220603202206044120220603202206054120220603202209105120220910202209115120220910202209125120220910202210016120221001202210026120221001202210036120221001202210046120221001202210056120221001202210066120221001202210076120221001202210086020221001202210096020221001202212310120230101202301010120230101202301020120230101202301211120230122202301221120230122202301231120230122202301241120230122202301251120230122202301261120230122202301271120230122202301281020230122202301291020230122202304052120230405202304233020230501202304293120230501202304303120230501202305013120230501202305023120230501202305033120230501202305063020230501202306224120230622202306234120230622202306244120230622202306254020230622202309295120230929202309306120231001202310016120231001202310026120231001202310036120231001202310046120231001202310056120231001202310066120231001202310076020231001202310086020231001202312300120240101202312310120240101202401010120240101202402041020240210202402101120240210202402111120240210202402121120240210202402131120240210202402141120240210202402151120240210202402161120240210202402171120240210202402181020240210202404042120240404202404052120240404202404062120240404202404072020240404202404283020240501202405013120240501202405023120240501202405033120240501202405043120240501202405053120240501202405113020240501202406084120240610202406094120240610202406104120240610202409145020240917202409155120240917202409165120240917202409175120240917202409296020241001202410016120241001202410026120241001202410036120241001202410046120241001202410056120241001202410066120241001202410076120241001202410126020241001202501010120250101202501261020250129202501281120250129202501291120250129202501301120250129202501311120250129202502011120250129202502021120250129202502031120250129202502041120250129202502081020250129202504042120250404202504052120250404202504062120250404202504273020250501202505013120250501202505023120250501202505033120250501202505043120250501202505053120250501202505314120250531202506014120250531202506024120250531202509287020251001202510017120251001202510027120251001202510037120251001202510047120251001202510057120251001202510067120251001202510077120251001202510087120251001202510117020251001" 14 | 15 | __NAMES_IN_USE = NAMES 16 | __DATA_IN_USE = __DATA 17 | 18 | def __init__(self): 19 | pass 20 | 21 | @staticmethod 22 | def __padding(n): 23 | return ("0" if n < 10 else "") + str(n) 24 | 25 | @staticmethod 26 | def __buildHolidayForward(s): 27 | day = s[0:8] 28 | name = HolidayUtil.__NAMES_IN_USE[ord(s[8:9]) - HolidayUtil.__ZERO] 29 | work = ord(s[9:10]) == HolidayUtil.__ZERO 30 | target = s[10:18] 31 | from .. import Holiday 32 | return Holiday(day, name, work, target) 33 | 34 | @staticmethod 35 | def __buildHolidayBackward(s): 36 | size = len(s) 37 | day = s[size - 18:size - 10] 38 | name = HolidayUtil.__NAMES_IN_USE[ord(s[size - 10:size - 9]) - HolidayUtil.__ZERO] 39 | work = ord(s[size - 9:size - 8]) == HolidayUtil.__ZERO 40 | target = s[size - 8:] 41 | from .. import Holiday 42 | return Holiday(day, name, work, target) 43 | 44 | @staticmethod 45 | def __findForward(key): 46 | start = HolidayUtil.__DATA_IN_USE.find(key) 47 | if start < 0: 48 | return None 49 | right = HolidayUtil.__DATA_IN_USE[start:] 50 | n = len(right) % HolidayUtil.__SIZE 51 | if n > 0: 52 | right = right[n:] 53 | while not right.startswith(key) and len(right) >= HolidayUtil.__SIZE: 54 | right = right[HolidayUtil.__SIZE:] 55 | return right 56 | 57 | @staticmethod 58 | def __findBackward(key): 59 | start = HolidayUtil.__DATA_IN_USE.rfind(key) 60 | if start < 0: 61 | return None 62 | key_size = len(key) 63 | left = HolidayUtil.__DATA_IN_USE[0:start + key_size] 64 | size = len(left) 65 | n = size % HolidayUtil.__SIZE 66 | if n > 0: 67 | left = left[0:size - n] 68 | size = len(left) 69 | while size - key_size != left.rfind(key) and size >= HolidayUtil.__SIZE: 70 | left = left[0:size - HolidayUtil.__SIZE] 71 | size = len(left) 72 | return left 73 | 74 | @staticmethod 75 | def __findHolidaysForward(key): 76 | arr = [] 77 | s = HolidayUtil.__findForward(key) 78 | if s is None: 79 | return arr 80 | while s.startswith(key): 81 | arr.append(HolidayUtil.__buildHolidayForward(s)) 82 | s = s[HolidayUtil.__SIZE:] 83 | return arr 84 | 85 | @staticmethod 86 | def __findHolidaysBackward(key): 87 | arr = [] 88 | s = HolidayUtil.__findBackward(key) 89 | if s is None: 90 | return arr 91 | size = len(s) 92 | key_size = len(key) 93 | 94 | while size - key_size == s.rfind(key): 95 | arr.append(HolidayUtil.__buildHolidayBackward(s)) 96 | s = s[0:size - HolidayUtil.__SIZE:] 97 | size = len(s) 98 | arr.reverse() 99 | return arr 100 | 101 | @staticmethod 102 | def __getHoliday(year, month=0, day=0): 103 | y = str(year) 104 | if month == 0 or day == 0: 105 | arr = HolidayUtil.__findHolidaysForward(y.replace("-", "")) 106 | else: 107 | arr = HolidayUtil.__findHolidaysForward(y + HolidayUtil.__padding(month) + HolidayUtil.__padding(day)) 108 | return None if len(arr) < 1 else arr[0] 109 | 110 | @staticmethod 111 | def __getHolidays(year, month=0): 112 | y = str(year) 113 | if month == 0: 114 | arr = HolidayUtil.__findHolidaysForward(y.replace("-", "")) 115 | else: 116 | arr = HolidayUtil.__findHolidaysForward(y + HolidayUtil.__padding(month)) 117 | return arr 118 | 119 | @staticmethod 120 | def __getHolidaysByTarget(year, month=0, day=0): 121 | y = str(year) 122 | if month == 0 or day == 0: 123 | arr = HolidayUtil.__findHolidaysBackward(y.replace("-", "")) 124 | else: 125 | arr = HolidayUtil.__findHolidaysBackward(y + HolidayUtil.__padding(month) + HolidayUtil.__padding(day)) 126 | return arr 127 | 128 | @staticmethod 129 | def getHoliday(year, month=0, day=0): 130 | """ 131 | 获取指定年月日的节假日信息,如果不存在,返回None 132 | :param year: 年或者yyyy-mm-dd格式的日期 133 | :param month: 月,数字1到12,如果year使用yyyy-mm-dd则不传该参数或设为0 134 | :param day: 日,数字1到31,如果year使用yyyy-mm-dd则不传该参数或设为0 135 | :return: Holiday或者None 136 | """ 137 | return HolidayUtil.__getHoliday(year, month, day) 138 | 139 | @staticmethod 140 | def getHolidays(year, month=0): 141 | return HolidayUtil.__getHolidays(year, month) 142 | 143 | @staticmethod 144 | def getHolidaysByTarget(year, month=0, day=0): 145 | return HolidayUtil.__getHolidaysByTarget(year, month, day) 146 | 147 | @staticmethod 148 | def fix(names, data): 149 | """ 150 | 修正或追加节假日数据。节假日名称下标从0开始,超过9的,按ASCII码表依次往后排列;调休标识0为上班,否则放假 151 | :param names: 用于替换默认的节假日名称列表,传None即可使用默认名称 152 | :param data: 需要修正或追加的节假日数据,每18位表示1天依次排列,格式:当天年月日YYYYMMDD(8位)+节假日名称下标(1位)+调休标识(1位)+节假日当天YYYYMMDD(8位)。例:202005023120200501代表2020-05-02为劳动节放假,对应节假日为2020-05-01 153 | :return: 154 | """ 155 | if names is not None: 156 | HolidayUtil.__NAMES_IN_USE = names 157 | if data is None: 158 | return 159 | append = "" 160 | while len(data) >= HolidayUtil.__SIZE: 161 | segment = data[:HolidayUtil.__SIZE] 162 | day = segment[:8] 163 | remove = HolidayUtil.__TAG_REMOVE == segment[8:9] 164 | holiday = HolidayUtil.getHoliday(day) 165 | if holiday is None: 166 | if not remove: 167 | append += segment 168 | else: 169 | name_index = -1 170 | for i in range(0, len(HolidayUtil.__NAMES_IN_USE)): 171 | if HolidayUtil.__NAMES_IN_USE[i] == holiday.getName(): 172 | name_index = i 173 | break 174 | if name_index > -1: 175 | old = day + chr(name_index + HolidayUtil.__ZERO) + ("0" if holiday.isWork() else "1") + holiday.getTarget().replace("-", "") 176 | HolidayUtil.__DATA_IN_USE = HolidayUtil.__DATA_IN_USE.replace(old, "" if remove else segment) 177 | data = data[HolidayUtil.__SIZE:] 178 | if len(append) > 0: 179 | HolidayUtil.__DATA_IN_USE += append 180 | -------------------------------------------------------------------------------- /lunar_python/util/SolarUtil.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from math import ceil 3 | 4 | 5 | class SolarUtil: 6 | """ 7 | 阳历工具 8 | """ 9 | 10 | # 星期 11 | WEEK = ("日", "一", "二", "三", "四", "五", "六") 12 | 13 | # 每月天数 14 | DAYS_OF_MONTH = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) 15 | 16 | # 星座 17 | XING_ZUO = ("白羊", "金牛", "双子", "巨蟹", "狮子", "处女", "天秤", "天蝎", "射手", "摩羯", "水瓶", "双鱼") 18 | 19 | # 日期对应的节日 20 | FESTIVAL = { 21 | "1-1": "元旦节", 22 | "2-14": "情人节", 23 | "3-8": "妇女节", 24 | "3-12": "植树节", 25 | "3-15": "消费者权益日", 26 | "4-1": "愚人节", 27 | "5-1": "劳动节", 28 | "5-4": "青年节", 29 | "6-1": "儿童节", 30 | "7-1": "建党节", 31 | "8-1": "建军节", 32 | "9-10": "教师节", 33 | "10-1": "国庆节", 34 | "12-24": "平安夜", 35 | "12-25": "圣诞节", 36 | "10-31": "万圣节前夜", 37 | "11-1": "万圣节" 38 | } 39 | 40 | # 几月第几个星期几对应的节日 41 | WEEK_FESTIVAL = { 42 | "3-0-1": "全国中小学生安全教育日", 43 | "5-2-0": "母亲节", 44 | "5-3-0": "全国助残日", 45 | "6-3-0": "父亲节", 46 | "9-3-6": "全民国防教育日", 47 | "10-1-1": "世界住房日", 48 | "11-4-4": "感恩节" 49 | } 50 | 51 | # 日期对应的非正式节日 52 | OTHER_FESTIVAL = { 53 | "1-8": ["周恩来逝世纪念日"], 54 | "1-10": ["中国人民警察节"], 55 | "1-14": ["日记情人节"], 56 | "1-21": ["列宁逝世纪念日"], 57 | "1-26": ["国际海关日"], 58 | "1-27": ["国际大屠杀纪念日"], 59 | "2-2": ["世界湿地日"], 60 | "2-4": ["世界抗癌日"], 61 | "2-7": ["京汉铁路罢工纪念日"], 62 | "2-10": ["国际气象节"], 63 | "2-19": ["邓小平逝世纪念日"], 64 | "2-20": ["世界社会公正日"], 65 | "2-21": ["国际母语日"], 66 | "2-24": ["第三世界青年日"], 67 | "3-1": ["国际海豹日"], 68 | "3-3": ["世界野生动植物日", "全国爱耳日"], 69 | "3-5": ["周恩来诞辰纪念日", "中国青年志愿者服务日"], 70 | "3-6": ["世界青光眼日"], 71 | "3-7": ["女生节"], 72 | "3-12": ["孙中山逝世纪念日"], 73 | "3-14": ["马克思逝世纪念日", "白色情人节"], 74 | "3-17": ["国际航海日"], 75 | "3-18": ["全国科技人才活动日", "全国爱肝日"], 76 | "3-20": ["国际幸福日"], 77 | "3-21": ["世界森林日", "世界睡眠日", "国际消除种族歧视日"], 78 | "3-22": ["世界水日"], 79 | "3-23": ["世界气象日"], 80 | "3-24": ["世界防治结核病日"], 81 | "3-29": ["中国黄花岗七十二烈士殉难纪念日"], 82 | "4-2": ["国际儿童图书日", "世界自闭症日"], 83 | "4-4": ["国际地雷行动日"], 84 | "4-7": ["世界卫生日"], 85 | "4-8": ["国际珍稀动物保护日"], 86 | "4-12": ["世界航天日"], 87 | "4-14": ["黑色情人节"], 88 | "4-15": ["全民国家安全教育日"], 89 | "4-22": ["世界地球日", "列宁诞辰纪念日"], 90 | "4-23": ["世界读书日"], 91 | "4-24": ["中国航天日"], 92 | "4-25": ["儿童预防接种宣传日"], 93 | "4-26": ["世界知识产权日", "全国疟疾日"], 94 | "4-28": ["世界安全生产与健康日"], 95 | "4-30": ["全国交通安全反思日"], 96 | "5-2": ["世界金枪鱼日"], 97 | "5-3": ["世界新闻自由日"], 98 | "5-5": ["马克思诞辰纪念日"], 99 | "5-8": ["世界红十字日"], 100 | "5-11": ["世界肥胖日"], 101 | "5-12": ["全国防灾减灾日", "护士节"], 102 | "5-14": ["玫瑰情人节"], 103 | "5-15": ["国际家庭日"], 104 | "5-19": ["中国旅游日"], 105 | "5-20": ["网络情人节"], 106 | "5-22": ["国际生物多样性日"], 107 | "5-25": ["525心理健康节"], 108 | "5-27": ["上海解放日"], 109 | "5-29": ["国际维和人员日"], 110 | "5-30": ["中国五卅运动纪念日"], 111 | "5-31": ["世界无烟日"], 112 | "6-3": ["世界自行车日"], 113 | "6-5": ["世界环境日"], 114 | "6-6": ["全国爱眼日"], 115 | "6-8": ["世界海洋日"], 116 | "6-11": ["中国人口日"], 117 | "6-14": ["世界献血日", "亲亲情人节"], 118 | "6-17": ["世界防治荒漠化与干旱日"], 119 | "6-20": ["世界难民日"], 120 | "6-21": ["国际瑜伽日"], 121 | "6-25": ["全国土地日"], 122 | "6-26": ["国际禁毒日", "联合国宪章日"], 123 | "7-1": ["香港回归纪念日"], 124 | "7-6": ["国际接吻日", "朱德逝世纪念日"], 125 | "7-7": ["七七事变纪念日"], 126 | "7-11": ["世界人口日", "中国航海日"], 127 | "7-14": ["银色情人节"], 128 | "7-18": ["曼德拉国际日"], 129 | "7-30": ["国际友谊日"], 130 | "8-3": ["男人节"], 131 | "8-5": ["恩格斯逝世纪念日"], 132 | "8-6": ["国际电影节"], 133 | "8-8": ["全民健身日"], 134 | "8-9": ["国际土著人日"], 135 | "8-12": ["国际青年节"], 136 | "8-14": ["绿色情人节"], 137 | "8-19": ["世界人道主义日", "中国医师节"], 138 | "8-22": ["邓小平诞辰纪念日"], 139 | "8-29": ["全国测绘法宣传日"], 140 | "9-3": ["中国抗日战争胜利纪念日"], 141 | "9-5": ["中华慈善日"], 142 | "9-8": ["世界扫盲日"], 143 | "9-9": ["毛泽东逝世纪念日", "全国拒绝酒驾日"], 144 | "9-14": ["世界清洁地球日", "相片情人节"], 145 | "9-15": ["国际民主日"], 146 | "9-16": ["国际臭氧层保护日"], 147 | "9-17": ["世界骑行日"], 148 | "9-18": ["九一八事变纪念日"], 149 | "9-20": ["全国爱牙日"], 150 | "9-21": ["国际和平日"], 151 | "9-27": ["世界旅游日"], 152 | "9-30": ["中国烈士纪念日"], 153 | "10-1": ["国际老年人日"], 154 | "10-2": ["国际非暴力日"], 155 | "10-4": ["世界动物日"], 156 | "10-11": ["国际女童日"], 157 | "10-10": ["辛亥革命纪念日"], 158 | "10-13": ["国际减轻自然灾害日", "中国少年先锋队诞辰日"], 159 | "10-14": ["葡萄酒情人节"], 160 | "10-16": ["世界粮食日"], 161 | "10-17": ["全国扶贫日"], 162 | "10-20": ["世界统计日"], 163 | "10-24": ["世界发展信息日", "程序员节"], 164 | "10-25": ["抗美援朝纪念日"], 165 | "11-5": ["世界海啸日"], 166 | "11-8": ["记者节"], 167 | "11-9": ["全国消防日"], 168 | "11-11": ["光棍节"], 169 | "11-12": ["孙中山诞辰纪念日"], 170 | "11-14": ["电影情人节"], 171 | "11-16": ["国际宽容日"], 172 | "11-17": ["国际大学生节"], 173 | "11-19": ["世界厕所日"], 174 | "11-28": ["恩格斯诞辰纪念日"], 175 | "11-29": ["国际声援巴勒斯坦人民日"], 176 | "12-1": ["世界艾滋病日"], 177 | "12-2": ["全国交通安全日"], 178 | "12-3": ["世界残疾人日"], 179 | "12-4": ["全国法制宣传日"], 180 | "12-5": ["世界弱能人士日", "国际志愿人员日"], 181 | "12-7": ["国际民航日"], 182 | "12-9": ["世界足球日", "国际反腐败日"], 183 | "12-10": ["世界人权日"], 184 | "12-11": ["国际山岳日"], 185 | "12-12": ["西安事变纪念日"], 186 | "12-13": ["国家公祭日"], 187 | "12-14": ["拥抱情人节"], 188 | "12-18": ["国际移徙者日"], 189 | "12-26": ["毛泽东诞辰纪念日"] 190 | } 191 | 192 | def __init__(self): 193 | pass 194 | 195 | @staticmethod 196 | def isLeapYear(year): 197 | """ 198 | 是否闰年 199 | :param year: 年 200 | :return: True/False 闰年/非闰年 201 | """ 202 | if year < 1600: 203 | return year % 4 == 0 204 | return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0) 205 | 206 | @staticmethod 207 | def getDaysOfYear(year): 208 | if 1582 == year: 209 | return 355 210 | d = 365 211 | if SolarUtil.isLeapYear(year): 212 | d = 366 213 | return d 214 | 215 | @staticmethod 216 | def getDaysOfMonth(year, month): 217 | """ 218 | 获取某年某月有多少天 219 | :param year: 年 220 | :param month: 月 221 | :return: 天数 222 | """ 223 | if 1582 == year and 10 == month: 224 | return 21 225 | d = SolarUtil.DAYS_OF_MONTH[month - 1] 226 | # 公历闰年2月多一天 227 | if month == 2 and SolarUtil.isLeapYear(year): 228 | d += 1 229 | return d 230 | 231 | @staticmethod 232 | def getDaysInYear(year, month, day): 233 | days = 0 234 | for i in range(1, month): 235 | days += SolarUtil.getDaysOfMonth(year, i) 236 | d = day 237 | if 1582 == year and 10 == month: 238 | if day >= 15: 239 | d -= 10 240 | elif day > 4: 241 | raise Exception("wrong solar year %d month %d day %d" % (year, month, day)) 242 | days += d 243 | return days 244 | 245 | @staticmethod 246 | def getWeeksOfMonth(year, month, start): 247 | """ 248 | 获取某年某月有多少周 249 | :param year: 年 250 | :param month: 月 251 | :param start: 星期几作为一周的开始,1234560分别代表星期一至星期天 252 | :return: 天数 253 | """ 254 | from .. import Solar 255 | return int(ceil((SolarUtil.getDaysOfMonth(year, month) + Solar.fromYmd(year, month, 1).getWeek() - start) * 1.0 / len(SolarUtil.WEEK))) 256 | 257 | @staticmethod 258 | def getDaysBetween(ay: int, am: int, ad: int, by: int, bm: int, bd: int): 259 | if ay == by: 260 | n = SolarUtil.getDaysInYear(by, bm, bd) - SolarUtil.getDaysInYear(ay, am, ad) 261 | elif ay > by: 262 | days = SolarUtil.getDaysOfYear(by) - SolarUtil.getDaysInYear(by, bm, bd) 263 | for i in range(by + 1, ay): 264 | days += SolarUtil.getDaysOfYear(i) 265 | days += SolarUtil.getDaysInYear(ay, am, ad) 266 | n = -days 267 | else: 268 | days = SolarUtil.getDaysOfYear(ay) - SolarUtil.getDaysInYear(ay, am, ad) 269 | for i in range(ay + 1, by): 270 | days += SolarUtil.getDaysOfYear(i) 271 | days += SolarUtil.getDaysInYear(by, bm, bd) 272 | n = days 273 | return n 274 | -------------------------------------------------------------------------------- /lunar_python/util/TaoUtil.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from ..TaoFestival import TaoFestival 3 | 4 | 5 | class TaoUtil: 6 | """ 7 | 道历工具 8 | """ 9 | 10 | # 三会日 11 | SAN_HUI = ("1-7", "7-7", "10-15") 12 | 13 | # 三元日 14 | SAN_YUAN = ("1-15", "7-15", "10-15") 15 | 16 | # 五腊日 17 | WU_LA = ("1-1", "5-5", "7-7", "10-1", "12-8") 18 | 19 | # 暗戊 20 | AN_WU = ("未", "戌", "辰", "寅", "午", "子", "酉", "申", "巳", "亥", "卯", "丑") 21 | 22 | # 八会日 23 | BA_HUI = { 24 | "丙午": "天会", 25 | "壬午": "地会", 26 | "壬子": "人会", 27 | "庚午": "日会", 28 | "庚申": "月会", 29 | "辛酉": "星辰会", 30 | "甲辰": "五行会", 31 | "甲戌": "四时会" 32 | } 33 | 34 | # 八节日 35 | BA_JIE = { 36 | "立春": "东北方度仙上圣天尊同梵炁始青天君下降", 37 | "春分": "东方玉宝星上天尊同青帝九炁天君下降", 38 | "立夏": "东南方好生度命天尊同梵炁始丹天君下降", 39 | "夏至": "南方玄真万福天尊同赤帝三炁天君下降", 40 | "立秋": "西南方太灵虚皇天尊同梵炁始素天君下降", 41 | "秋分": "西方太妙至极天尊同白帝七炁天君下降", 42 | "立冬": "西北方无量太华天尊同梵炁始玄天君下降", 43 | "冬至": "北方玄上玉宸天尊同黑帝五炁天君下降" 44 | } 45 | 46 | # 日期对应的节日 47 | FESTIVAL = { 48 | "1-1": [TaoFestival("天腊之辰", "天腊,此日五帝会于东方九炁青天")], 49 | "1-3": [TaoFestival("郝真人圣诞"), TaoFestival("孙真人圣诞")], 50 | "1-5": [TaoFestival("孙祖清静元君诞")], 51 | "1-7": [TaoFestival("举迁赏会", "此日上元赐福,天官同地水二官考校罪福")], 52 | "1-9": [TaoFestival("玉皇上帝圣诞")], 53 | "1-13": [TaoFestival("关圣帝君飞升")], 54 | "1-15": [TaoFestival("上元天官圣诞"), TaoFestival("老祖天师圣诞")], 55 | "1-19": [TaoFestival("长春邱真人(邱处机)圣诞")], 56 | "1-28": [TaoFestival("许真君(许逊天师)圣诞")], 57 | "2-1": [TaoFestival("勾陈天皇大帝圣诞"), TaoFestival("长春刘真人(刘渊然)圣诞")], 58 | "2-2": [TaoFestival("土地正神诞"), TaoFestival("姜太公圣诞")], 59 | "2-3": [TaoFestival("文昌梓潼帝君圣诞")], 60 | "2-6": [TaoFestival("东华帝君圣诞")], 61 | "2-13": [TaoFestival("度人无量葛真君圣诞")], 62 | "2-15": [TaoFestival("太清道德天尊(太上老君)圣诞")], 63 | "2-19": [TaoFestival("慈航真人圣诞")], 64 | "3-1": [TaoFestival("谭祖(谭处端)长真真人圣诞")], 65 | "3-3": [TaoFestival("玄天上帝圣诞")], 66 | "3-6": [TaoFestival("眼光娘娘圣诞")], 67 | "3-15": [TaoFestival("天师张大真人圣诞"), TaoFestival("财神赵公元帅圣诞")], 68 | "3-16": [TaoFestival("三茅真君得道之辰"), TaoFestival("中岳大帝圣诞")], 69 | "3-18": [TaoFestival("王祖(王处一)玉阳真人圣诞"), TaoFestival("后土娘娘圣诞")], 70 | "3-19": [TaoFestival("太阳星君圣诞")], 71 | "3-20": [TaoFestival("子孙娘娘圣诞")], 72 | "3-23": [TaoFestival("天后妈祖圣诞")], 73 | "3-26": [TaoFestival("鬼谷先师诞")], 74 | "3-28": [TaoFestival("东岳大帝圣诞")], 75 | "4-1": [TaoFestival("长生谭真君成道之辰")], 76 | "4-10": [TaoFestival("何仙姑圣诞")], 77 | "4-14": [TaoFestival("吕祖纯阳祖师圣诞")], 78 | "4-15": [TaoFestival("钟离祖师圣诞")], 79 | "4-18": [TaoFestival("北极紫微大帝圣诞"), TaoFestival("泰山圣母碧霞元君诞"), TaoFestival("华佗神医先师诞")], 80 | "4-20": [TaoFestival("眼光圣母娘娘诞")], 81 | "4-28": [TaoFestival("神农先帝诞")], 82 | "5-1": [TaoFestival("南极长生大帝圣诞")], 83 | "5-5": [TaoFestival("地腊之辰", "地腊,此日五帝会于南方三炁丹天"), TaoFestival("南方雷祖圣诞"), TaoFestival("地祗温元帅圣诞"), TaoFestival("雷霆邓天君圣诞")], 84 | "5-11": [TaoFestival("城隍爷圣诞")], 85 | "5-13": [TaoFestival("关圣帝君降神"), TaoFestival("关平太子圣诞")], 86 | "5-18": [TaoFestival("张天师圣诞")], 87 | "5-20": [TaoFestival("马祖丹阳真人圣诞")], 88 | "5-29": [TaoFestival("紫青白祖师圣诞")], 89 | "6-1": [TaoFestival("南斗星君下降")], 90 | "6-2": [TaoFestival("南斗星君下降")], 91 | "6-3": [TaoFestival("南斗星君下降")], 92 | "6-4": [TaoFestival("南斗星君下降")], 93 | "6-5": [TaoFestival("南斗星君下降")], 94 | "6-6": [TaoFestival("南斗星君下降")], 95 | "6-10": [TaoFestival("刘海蟾祖师圣诞")], 96 | "6-15": [TaoFestival("灵官王天君圣诞")], 97 | "6-19": [TaoFestival("慈航(观音)成道日")], 98 | "6-23": [TaoFestival("火神圣诞")], 99 | "6-24": [TaoFestival("南极大帝中方雷祖圣诞"), TaoFestival("关圣帝君圣诞")], 100 | "6-26": [TaoFestival("二郎真君圣诞")], 101 | "7-7": [TaoFestival("道德腊之辰", "道德腊,此日五帝会于西方七炁素天"), TaoFestival("庆生中会", "此日中元赦罪,地官同天水二官考校罪福")], 102 | "7-12": [TaoFestival("西方雷祖圣诞")], 103 | "7-15": [TaoFestival("中元地官大帝圣诞")], 104 | "7-18": [TaoFestival("王母娘娘圣诞")], 105 | "7-20": [TaoFestival("刘祖(刘处玄)长生真人圣诞")], 106 | "7-22": [TaoFestival("财帛星君文财神增福相公李诡祖圣诞")], 107 | "7-26": [TaoFestival("张三丰祖师圣诞")], 108 | "8-1": [TaoFestival("许真君飞升日")], 109 | "8-3": [TaoFestival("九天司命灶君诞")], 110 | "8-5": [TaoFestival("北方雷祖圣诞")], 111 | "8-10": [TaoFestival("北岳大帝诞辰")], 112 | "8-15": [TaoFestival("太阴星君诞")], 113 | "9-1": [TaoFestival("北斗九皇降世之辰")], 114 | "9-2": [TaoFestival("北斗九皇降世之辰")], 115 | "9-3": [TaoFestival("北斗九皇降世之辰")], 116 | "9-4": [TaoFestival("北斗九皇降世之辰")], 117 | "9-5": [TaoFestival("北斗九皇降世之辰")], 118 | "9-6": [TaoFestival("北斗九皇降世之辰")], 119 | "9-7": [TaoFestival("北斗九皇降世之辰")], 120 | "9-8": [TaoFestival("北斗九皇降世之辰")], 121 | "9-9": [TaoFestival("北斗九皇降世之辰"), TaoFestival("斗姥元君圣诞"), TaoFestival("重阳帝君圣诞"), TaoFestival("玄天上帝飞升"), TaoFestival("酆都大帝圣诞")], 122 | "9-22": [TaoFestival("增福财神诞")], 123 | "9-23": [TaoFestival("萨翁真君圣诞")], 124 | "9-28": [TaoFestival("五显灵官马元帅圣诞")], 125 | "10-1": [TaoFestival("民岁腊之辰", "民岁腊,此日五帝会于北方五炁黑天"), TaoFestival("东皇大帝圣诞")], 126 | "10-3": [TaoFestival("三茅应化真君圣诞")], 127 | "10-6": [TaoFestival("天曹诸司五岳五帝圣诞")], 128 | "10-15": [TaoFestival("下元水官大帝圣诞"), TaoFestival("建生大会", "此日下元解厄,水官同天地二官考校罪福")], 129 | "10-18": [TaoFestival("地母娘娘圣诞")], 130 | "10-19": [TaoFestival("长春邱真君飞升")], 131 | "10-20": [TaoFestival("虚靖天师(即三十代天师弘悟张真人)诞")], 132 | "11-6": [TaoFestival("西岳大帝圣诞")], 133 | "11-9": [TaoFestival("湘子韩祖圣诞")], 134 | "11-11": [TaoFestival("太乙救苦天尊圣诞")], 135 | "11-26": [TaoFestival("北方五道圣诞")], 136 | "12-8": [TaoFestival("王侯腊之辰", "王侯腊,此日五帝会于上方玄都玉京")], 137 | "12-16": [TaoFestival("南岳大帝圣诞"), TaoFestival("福德正神诞")], 138 | "12-20": [TaoFestival("鲁班先师圣诞")], 139 | "12-21": [TaoFestival("天猷上帝圣诞")], 140 | "12-22": [TaoFestival("重阳祖师圣诞")], 141 | "12-23": [TaoFestival("祭灶王", "最适宜谢旧年太岁,开启拜新年太岁")], 142 | "12-25": [TaoFestival("玉帝巡天"), TaoFestival("天神下降")], 143 | "12-29": [TaoFestival("清静孙真君(孙不二)成道")] 144 | } 145 | 146 | def __init__(self): 147 | pass 148 | -------------------------------------------------------------------------------- /lunar_python/util/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from .HolidayUtil import HolidayUtil 3 | from .ShouXingUtil import ShouXingUtil 4 | from .SolarUtil import SolarUtil 5 | from .LunarUtil import LunarUtil 6 | from .FotoUtil import FotoUtil 7 | from .TaoUtil import TaoUtil 8 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name='lunar_python', 5 | version='1.4.4', 6 | packages=['lunar_python', 'lunar_python.util', 'lunar_python.eightchar'], 7 | url='https://github.com/6tail/lunar-python', 8 | license='MIT', 9 | author='6tail', 10 | author_email='6tail@6tail.cn', 11 | description='lunar is a calendar library for Solar and Chinese Lunar.', 12 | long_description='lunar is a calendar library for Solar and Chinese Lunar.', 13 | keywords='solar lunar' 14 | ) 15 | -------------------------------------------------------------------------------- /test/ChineseTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | 5 | class ChineseTest(unittest.TestCase): 6 | def test(self): 7 | gz = "甲午" 8 | g = gz[:1] 9 | z = gz[1:] 10 | self.assertEqual("甲", g) 11 | self.assertEqual("午", z) 12 | -------------------------------------------------------------------------------- /test/EightCharTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from datetime import datetime 4 | 5 | from lunar_python import Solar, Lunar 6 | 7 | 8 | class EightCharTest(unittest.TestCase): 9 | 10 | def test_gan_zhi(self): 11 | solar = Solar.fromYmdHms(2005, 12, 23, 8, 37, 0) 12 | lunar = solar.getLunar() 13 | eight_char = lunar.getEightChar() 14 | self.assertEqual("乙酉", eight_char.getYear()) 15 | self.assertEqual("戊子", eight_char.getMonth()) 16 | self.assertEqual("辛巳", eight_char.getDay()) 17 | self.assertEqual("壬辰", eight_char.getTime()) 18 | 19 | def test_shen_gong(self): 20 | lunar = Solar.fromYmdHms(1995, 12, 18, 10, 28, 0).getLunar() 21 | self.assertEqual("壬午", lunar.getEightChar().getShenGong()) 22 | 23 | def test_shen_gong1(self): 24 | lunar = Solar.fromYmdHms(1994, 12, 6, 2, 0, 0).getLunar() 25 | self.assertEqual("丁丑", lunar.getEightChar().getShenGong()) 26 | 27 | def test_shen_gong2(self): 28 | lunar = Solar.fromYmdHms(1990, 12, 11, 6, 0, 0).getLunar() 29 | self.assertEqual("庚辰", lunar.getEightChar().getShenGong()) 30 | 31 | def test_shen_gong3(self): 32 | lunar = Solar.fromYmdHms(1993, 5, 23, 4, 0, 0).getLunar() 33 | self.assertEqual("庚申", lunar.getEightChar().getShenGong()) 34 | 35 | def test4(self): 36 | lunar = Lunar.fromYmd(1985, 12, 27) 37 | self.assertEqual("1995-11-05", lunar.getEightChar().getYun(1).getStartSolar().toYmd()) 38 | 39 | def test5(self): 40 | lunar = Lunar.fromYmd(1985, 1, 27) 41 | self.assertEqual("1989-03-28", lunar.getEightChar().getYun(1).getStartSolar().toYmd()) 42 | 43 | def test6(self): 44 | lunar = Lunar.fromYmd(1986, 12, 27) 45 | self.assertEqual("1990-04-15", lunar.getEightChar().getYun(1).getStartSolar().toYmd()) 46 | 47 | def test7(self): 48 | solar = Solar.fromYmdHms(2022, 8, 28, 1, 50, 0) 49 | lunar = solar.getLunar() 50 | eight_char = lunar.getEightChar() 51 | self.assertEqual("壬寅", eight_char.getYear()) 52 | self.assertEqual("戊申", eight_char.getMonth()) 53 | self.assertEqual("癸丑", eight_char.getDay()) 54 | self.assertEqual("癸丑", eight_char.getTime()) 55 | 56 | def test8(self): 57 | lunar = Lunar.fromYmdHms(2022, 8, 2, 1, 50, 0) 58 | eight_char = lunar.getEightChar() 59 | self.assertEqual("壬寅", eight_char.getYear()) 60 | self.assertEqual("戊申", eight_char.getMonth()) 61 | self.assertEqual("癸丑", eight_char.getDay()) 62 | self.assertEqual("癸丑", eight_char.getTime()) 63 | 64 | def test9(self): 65 | lunar = Lunar.fromDate(datetime.strptime('2022-08-28 01:50:00', '%Y-%m-%d %H:%M:%S')) 66 | eight_char = lunar.getEightChar() 67 | self.assertEqual("壬寅", eight_char.getYear()) 68 | self.assertEqual("戊申", eight_char.getMonth()) 69 | self.assertEqual("癸丑", eight_char.getDay()) 70 | self.assertEqual("癸丑", eight_char.getTime()) 71 | 72 | def test10(self): 73 | lunar = Solar.fromYmdHms(1988, 2, 15, 23, 30, 0).getLunar() 74 | eight_char = lunar.getEightChar() 75 | self.assertEqual("戊辰", eight_char.getYear()) 76 | self.assertEqual("甲寅", eight_char.getMonth()) 77 | self.assertEqual("庚子", eight_char.getDay()) 78 | self.assertEqual("戊子", eight_char.getTime()) 79 | 80 | def test11(self): 81 | lunar = Lunar.fromYmdHms(1987, 12, 28, 23, 30, 0) 82 | eight_char = lunar.getEightChar() 83 | self.assertEqual("戊辰", eight_char.getYear()) 84 | self.assertEqual("甲寅", eight_char.getMonth()) 85 | self.assertEqual("庚子", eight_char.getDay()) 86 | self.assertEqual("戊子", eight_char.getTime()) 87 | 88 | def test12(self): 89 | solar_list = Solar.fromBaZi("己卯", "辛未", "甲戌", "癸酉") 90 | self.assertLess(1, len(solar_list)) 91 | 92 | def test13(self): 93 | lunar = Lunar.fromYmdHms(1991, 4, 5, 3, 37, 0) 94 | eight_char = lunar.getEightChar() 95 | self.assertEqual("辛未", eight_char.getYear()) 96 | self.assertEqual("癸巳", eight_char.getMonth()) 97 | self.assertEqual("戊子", eight_char.getDay()) 98 | self.assertEqual("甲寅", eight_char.getTime()) 99 | 100 | def test14(self): 101 | solar_list = Solar.fromBaZi("己卯", "辛未", "甲戌", "壬申") 102 | actual = [] 103 | for solar in solar_list: 104 | actual.append(solar.toYmdHms()) 105 | expected = ["1939-08-05 16:00:00", "1999-07-21 16:00:00"] 106 | self.assertListEqual(expected, actual) 107 | 108 | def test15(self): 109 | solar_list = Solar.fromBaZi("庚子", "戊子", "己卯", "庚午") 110 | actual = [] 111 | for solar in solar_list: 112 | actual.append(solar.toYmdHms()) 113 | expected = ["1901-01-01 12:00:00", "1960-12-17 12:00:00"] 114 | self.assertListEqual(expected, actual) 115 | 116 | def test16(self): 117 | solar_list = Solar.fromBaZi("癸卯", "甲寅", "癸丑", "甲子", 2, 1843) 118 | actual = [] 119 | for solar in solar_list: 120 | actual.append(solar.toYmdHms()) 121 | expected = ["1843-02-08 23:00:00", "2023-02-24 23:00:00"] 122 | self.assertListEqual(expected, actual) 123 | 124 | def test17(self): 125 | solar_list = Solar.fromBaZi("己亥", "丁丑", "壬寅", "戊申") 126 | actual = [] 127 | for solar in solar_list: 128 | actual.append(solar.toYmdHms()) 129 | expected = ["1900-01-29 16:00:00", "1960-01-15 16:00:00"] 130 | self.assertListEqual(expected, actual) 131 | 132 | def test18(self): 133 | solar_list = Solar.fromBaZi("己亥", "丙子", "癸酉", "庚申") 134 | actual = [] 135 | for solar in solar_list: 136 | actual.append(solar.toYmdHms()) 137 | expected = ["1959-12-17 16:00:00"] 138 | self.assertListEqual(expected, actual) 139 | 140 | def test19(self): 141 | solar_list = Solar.fromBaZi("丁卯", "丁未", "甲申", "乙丑", 1, 1900) 142 | actual = [] 143 | for solar in solar_list: 144 | actual.append(solar.toYmdHms()) 145 | expected = ["1987-08-03 02:00:00"] 146 | self.assertListEqual(expected, actual) 147 | -------------------------------------------------------------------------------- /test/FotoTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import Foto, Lunar 4 | 5 | 6 | class FotoTest(unittest.TestCase): 7 | def test(self): 8 | foto = Foto.fromLunar(Lunar.fromYmd(2021, 10, 14)) 9 | self.assertEqual("二五六五年十月十四 (三元降) (四天王巡行)", foto.toFullString()) 10 | 11 | def test1(self): 12 | foto = Foto.fromLunar(Lunar.fromYmd(2020, 4, 13)) 13 | self.assertEqual("氐", foto.getXiu()) 14 | self.assertEqual("土", foto.getZheng()) 15 | self.assertEqual("貉", foto.getAnimal()) 16 | self.assertEqual("东", foto.getGong()) 17 | self.assertEqual("青龙", foto.getShou()) 18 | 19 | def test2(self): 20 | foto = Foto.fromLunar(Lunar.fromYmd(2021, 3, 16)) 21 | self.assertListEqual(["准提菩萨圣诞"], foto.getOtherFestivals()) 22 | -------------------------------------------------------------------------------- /test/HolidayTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from lunar_python.util import HolidayUtil 5 | 6 | 7 | class HolidayTest(unittest.TestCase): 8 | def test(self): 9 | holiday = HolidayUtil.getHoliday(2010, 1, 1) 10 | self.assertEqual("元旦节", holiday.getName()) 11 | 12 | HolidayUtil.fix(None, "20100101~000000000000000000000000000") 13 | holiday = HolidayUtil.getHoliday(2010, 1, 1) 14 | self.assertIsNone(holiday) 15 | -------------------------------------------------------------------------------- /test/HouTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import Solar 4 | 5 | 6 | class HouTest(unittest.TestCase): 7 | 8 | def test1(self): 9 | solar = Solar.fromYmd(2021, 12, 21) 10 | self.assertEqual("冬至 初候", solar.getLunar().getHou()) 11 | 12 | def test2(self): 13 | solar = Solar.fromYmd(2021, 12, 26) 14 | self.assertEqual("冬至 二候", solar.getLunar().getHou()) 15 | 16 | def test3(self): 17 | solar = Solar.fromYmd(2021, 12, 31) 18 | self.assertEqual("冬至 三候", solar.getLunar().getHou()) 19 | 20 | def test4(self): 21 | solar = Solar.fromYmd(2022, 1, 5) 22 | self.assertEqual("小寒 初候", solar.getLunar().getHou()) 23 | -------------------------------------------------------------------------------- /test/JieQiTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import Lunar, Solar 4 | 5 | 6 | class JieQiTest(unittest.TestCase): 7 | def test7(self): 8 | lunar = Lunar.fromYmd(2012, 9, 1) 9 | self.assertEqual("2012-09-07 13:29:01", lunar.getJieQiTable()["白露"].toYmdHms()) 10 | 11 | def test8(self): 12 | lunar = Lunar.fromYmd(2050, 12, 1) 13 | self.assertEqual("2050-12-07 06:40:53", lunar.getJieQiTable()["DA_XUE"].toYmdHms()) 14 | 15 | def test1(self): 16 | solar = Solar.fromYmd(2021, 12, 21) 17 | lunar = solar.getLunar() 18 | self.assertEqual("冬至", lunar.getJieQi()) 19 | self.assertEqual("", lunar.getJie()) 20 | self.assertEqual("冬至", lunar.getQi()) 21 | 22 | def test2(self): 23 | lunar = Lunar.fromYmd(2023, 6, 1) 24 | self.assertEqual("2022-12-22 05:48:01", lunar.getJieQiTable()["冬至"].toYmdHms()) 25 | -------------------------------------------------------------------------------- /test/LunarMonthTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import LunarMonth 4 | 5 | 6 | class LunarMonthTest(unittest.TestCase): 7 | 8 | def test(self): 9 | month = LunarMonth.fromYm(2023, 1) 10 | self.assertEqual(1, month.getIndex()) 11 | self.assertEqual("甲寅", month.getGanZhi()) 12 | 13 | def test1(self): 14 | month = LunarMonth.fromYm(2023, -2) 15 | self.assertEqual(3, month.getIndex()) 16 | self.assertEqual("丙辰", month.getGanZhi()) 17 | 18 | def test2(self): 19 | month = LunarMonth.fromYm(2023, 3) 20 | self.assertEqual(4, month.getIndex()) 21 | self.assertEqual("丁巳", month.getGanZhi()) 22 | 23 | def test3(self): 24 | month = LunarMonth.fromYm(2024, 1) 25 | self.assertEqual(1, month.getIndex()) 26 | self.assertEqual("丙寅", month.getGanZhi()) 27 | 28 | def test4(self): 29 | month = LunarMonth.fromYm(2023, 12) 30 | self.assertEqual(13, month.getIndex()) 31 | self.assertEqual("丙寅", month.getGanZhi()) 32 | 33 | def test5(self): 34 | month = LunarMonth.fromYm(2022, 1) 35 | self.assertEqual(1, month.getIndex()) 36 | self.assertEqual("壬寅", month.getGanZhi()) 37 | -------------------------------------------------------------------------------- /test/LunarTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import Lunar, Solar 4 | 5 | 6 | class LunarTest(unittest.TestCase): 7 | 8 | def test(self): 9 | date = Lunar.fromYmdHms(2019, 3, 27, 0, 0, 0) 10 | self.assertEqual("二〇一九年三月廿七", date.toString()) 11 | self.assertEqual("二〇一九年三月廿七 己亥(猪)年 戊辰(龙)月 戊戌(狗)日 子(鼠)时 纳音[平地木 大林木 平地木 桑柘木] 星期三 西方白虎 星宿[参水猿](吉) 彭祖百忌[戊不受田田主不祥 戌不吃犬作怪上床] 喜神方位[巽](东南) 阳贵神方位[艮](东北) 阴贵神方位[坤](西南) 福神方位[艮](东北) 财神方位[坎](正北) 冲[(壬辰)龙] 煞[北]", date.toFullString()) 12 | self.assertEqual("2019-05-01", date.getSolar().toString()) 13 | self.assertEqual("2019-05-01 00:00:00 星期三 (劳动节) 金牛座", date.getSolar().toFullString()) 14 | 15 | def test1(self): 16 | solar = Solar.fromYmdHms(100, 1, 1, 12, 0, 0) 17 | self.assertEqual("九九年腊月初二", solar.getLunar().toString()) 18 | 19 | def test2(self): 20 | solar = Solar.fromYmdHms(3218, 12, 31, 12, 0, 0) 21 | self.assertEqual("三二一八年冬月廿二", solar.getLunar().toString()) 22 | 23 | def test3(self): 24 | lunar = Lunar.fromYmdHms(5, 1, 6, 12, 0, 0) 25 | self.assertEqual("0005-02-03", lunar.getSolar().toString()) 26 | 27 | def test4(self): 28 | lunar = Lunar.fromYmdHms(9997, 12, 21, 12, 0, 0) 29 | self.assertEqual("9998-01-11", lunar.getSolar().toString()) 30 | 31 | def test5(self): 32 | lunar = Lunar.fromYmdHms(1905, 1, 1, 12, 0, 0) 33 | self.assertEqual("1905-02-04", lunar.getSolar().toString()) 34 | 35 | def test6(self): 36 | lunar = Lunar.fromYmdHms(2038, 12, 29, 12, 0, 0) 37 | self.assertEqual("2039-01-23", lunar.getSolar().toString()) 38 | 39 | def test7(self): 40 | lunar = Lunar.fromYmdHms(2020, -4, 2, 13, 0, 0) 41 | self.assertEqual("二〇二〇年闰四月初二", lunar.toString()) 42 | self.assertEqual("2020-05-24", lunar.getSolar().toString()) 43 | 44 | def test8(self): 45 | lunar = Lunar.fromYmdHms(2020, 12, 10, 13, 0, 0) 46 | self.assertEqual("二〇二〇年腊月初十", lunar.toString()) 47 | self.assertEqual("2021-01-22", lunar.getSolar().toString()) 48 | 49 | def test9(self): 50 | lunar = Lunar.fromYmdHms(1500, 1, 1, 12, 0, 0) 51 | self.assertEqual("1500-01-31", lunar.getSolar().toString()) 52 | 53 | def test10(self): 54 | lunar = Lunar.fromYmdHms(1500, 12, 29, 12, 0, 0) 55 | self.assertEqual("1501-01-18", lunar.getSolar().toString()) 56 | 57 | def test11(self): 58 | solar = Solar.fromYmdHms(1500, 1, 1, 12, 0, 0) 59 | self.assertEqual("一四九九年腊月初一", solar.getLunar().toString()) 60 | 61 | def test12(self): 62 | solar = Solar.fromYmdHms(1500, 12, 31, 12, 0, 0) 63 | self.assertEqual("一五〇〇年腊月十一", solar.getLunar().toString()) 64 | 65 | def test13(self): 66 | solar = Solar.fromYmdHms(1582, 10, 4, 12, 0, 0) 67 | self.assertEqual("一五八二年九月十八", solar.getLunar().toString()) 68 | 69 | def test14(self): 70 | solar = Solar.fromYmdHms(1582, 10, 15, 12, 0, 0) 71 | self.assertEqual("一五八二年九月十九", solar.getLunar().toString()) 72 | 73 | def test15(self): 74 | lunar = Lunar.fromYmdHms(1582, 9, 18, 12, 0, 0) 75 | self.assertEqual("1582-10-04", lunar.getSolar().toString()) 76 | 77 | def test16(self): 78 | lunar = Lunar.fromYmdHms(1582, 9, 19, 12, 0, 0) 79 | self.assertEqual("1582-10-15", lunar.getSolar().toString()) 80 | 81 | def test17(self): 82 | lunar = Lunar.fromYmdHms(2019, 12, 12, 11, 22, 0) 83 | self.assertEqual("2020-01-06", lunar.getSolar().toString()) 84 | 85 | def test18(self): 86 | lunar = Lunar.fromYmd(2021, 12, 29) 87 | self.assertEqual("除夕", lunar.getFestivals()[0]) 88 | 89 | def test19(self): 90 | lunar = Lunar.fromYmd(2020, 12, 30) 91 | self.assertEqual("除夕", lunar.getFestivals()[0]) 92 | 93 | def test20(self): 94 | lunar = Lunar.fromYmd(2020, 12, 29) 95 | self.assertEqual(0, len(lunar.getFestivals())) 96 | 97 | def test21(self): 98 | solar = Solar.fromYmd(2022, 1, 31) 99 | lunar = solar.getLunar() 100 | self.assertEqual("除夕", lunar.getFestivals()[0]) 101 | 102 | def test22(self): 103 | lunar = Lunar.fromYmd(2033, -11, 1) 104 | self.assertEqual('2033-12-22', lunar.getSolar().toYmd()) 105 | 106 | def test25(self): 107 | solar = Solar.fromYmdHms(2021, 6, 7, 21, 18, 0) 108 | self.assertEqual('二〇二一年四月廿七', solar.getLunar().toString()) 109 | 110 | def test26(self): 111 | lunar = Lunar.fromYmdHms(2021, 6, 7, 21, 18, 0) 112 | self.assertEqual('2021-07-16', lunar.getSolar().toString()) 113 | 114 | def testNext(self): 115 | solar = Solar.fromYmdHms(2020, 1, 10, 12, 0, 0) 116 | lunar = solar.getLunar() 117 | for i in range(-1, 1): 118 | self.assertEqual(solar.next(i).getLunar().toFullString(), lunar.next(i).toFullString()) 119 | 120 | def test27(self): 121 | solar = Solar.fromYmd(1989, 4, 28) 122 | self.assertEqual(23, solar.getLunar().getDay()) 123 | 124 | def test28(self): 125 | solar = Solar.fromYmd(1990, 10, 8) 126 | self.assertEqual("乙酉", solar.getLunar().getMonthInGanZhiExact()) 127 | 128 | def test29(self): 129 | solar = Solar.fromYmd(1990, 10, 9) 130 | self.assertEqual("丙戌", solar.getLunar().getMonthInGanZhiExact()) 131 | 132 | def test30(self): 133 | solar = Solar.fromYmd(1990, 10, 8) 134 | self.assertEqual("丙戌", solar.getLunar().getMonthInGanZhi()) 135 | 136 | def test31(self): 137 | solar = Solar.fromYmdHms(1987, 4, 17, 9, 0, 0) 138 | self.assertEqual("一九八七年三月二十", solar.getLunar().toString()) 139 | 140 | def test32(self): 141 | lunar = Lunar.fromYmd(2034, 1, 1) 142 | self.assertEqual("2034-02-19", lunar.getSolar().toYmd()) 143 | 144 | def test33(self): 145 | lunar = Lunar.fromYmd(2033, 12, 1) 146 | self.assertEqual("2034-01-20", lunar.getSolar().toYmd()) 147 | 148 | def test34(self): 149 | lunar = Lunar.fromYmd(37, -12, 1) 150 | self.assertEqual("闰腊", lunar.getMonthInChinese()) 151 | 152 | def test36(self): 153 | solar = Solar.fromYmd(5553, 1, 22) 154 | self.assertEqual("五五五二年闰腊月初二", solar.getLunar().toString()) 155 | 156 | def test37(self): 157 | solar = Solar.fromYmd(7013, 12, 24) 158 | self.assertEqual("七〇一三年闰冬月初四", solar.getLunar().toString()) 159 | 160 | def test38(self): 161 | lunar = Lunar.fromYmd(7013, -11, 4) 162 | self.assertEqual("7013-12-24", lunar.getSolar().toString()) 163 | 164 | def test39(self): 165 | solar = Solar.fromYmd(1987, 4, 12) 166 | lunar = solar.getLunar() 167 | self.assertEqual("一九八七年三月十五", lunar.toString()) 168 | 169 | def test40(self): 170 | solar = Solar.fromYmd(1987, 4, 13) 171 | lunar = solar.getLunar() 172 | self.assertEqual("一九八七年三月十六", lunar.toString()) 173 | 174 | def test41(self): 175 | solar = Solar.fromYmd(4, 2, 10) 176 | lunar = solar.getLunar() 177 | self.assertEqual("鼠", lunar.getYearShengXiao()) 178 | 179 | def test42(self): 180 | solar = Solar.fromYmd(4, 2, 9) 181 | lunar = solar.getLunar() 182 | self.assertEqual("猪", lunar.getYearShengXiao()) 183 | 184 | def test43(self): 185 | solar = Solar.fromYmd(2017, 2, 15) 186 | lunar = solar.getLunar() 187 | self.assertEqual("子命互禄 辛命进禄", lunar.getDayLu()) 188 | 189 | def test44(self): 190 | solar = Solar.fromYmd(2017, 2, 16) 191 | lunar = solar.getLunar() 192 | self.assertEqual("寅命互禄", lunar.getDayLu()) 193 | 194 | def test48(self): 195 | solar = Solar.fromYmd(2021, 11, 13) 196 | lunar = solar.getLunar() 197 | self.assertEqual("碓磨厕 外东南", lunar.getDayPositionTai()) 198 | 199 | def test49(self): 200 | solar = Solar.fromYmd(2021, 11, 12) 201 | lunar = solar.getLunar() 202 | self.assertEqual("占门碓 外东南", lunar.getDayPositionTai()) 203 | 204 | def test50(self): 205 | solar = Solar.fromYmd(2021, 11, 13) 206 | lunar = solar.getLunar() 207 | self.assertEqual("西南", lunar.getDayPositionFuDesc()) 208 | 209 | def test51(self): 210 | solar = Solar.fromYmd(2021, 11, 12) 211 | lunar = solar.getLunar() 212 | self.assertEqual("正北", lunar.getDayPositionFuDesc()) 213 | 214 | def test52(self): 215 | solar = Solar.fromYmd(2011, 11, 12) 216 | lunar = solar.getLunar() 217 | self.assertEqual("厨灶厕 外西南", lunar.getDayPositionTai()) 218 | 219 | def test53(self): 220 | solar = Solar.fromYmd(1722, 9, 25) 221 | lunar = solar.getLunar() 222 | self.assertEqual("秋社", lunar.getOtherFestivals()[0]) 223 | 224 | def test54(self): 225 | solar = Solar.fromYmd(840, 9, 14) 226 | lunar = solar.getLunar() 227 | self.assertEqual("秋社", lunar.getOtherFestivals()[0]) 228 | 229 | def test55(self): 230 | solar = Solar.fromYmd(2022, 3, 16) 231 | lunar = solar.getLunar() 232 | self.assertEqual("春社", lunar.getOtherFestivals()[0]) 233 | 234 | def test56(self): 235 | solar = Solar.fromYmd(2021, 3, 21) 236 | lunar = solar.getLunar() 237 | self.assertEqual("春社", lunar.getOtherFestivals()[0]) 238 | 239 | def test57(self): 240 | self.assertEqual("1582-10-04", Lunar.fromYmd(1582, 9, 18).getSolar().toYmd()) 241 | 242 | def test58(self): 243 | self.assertEqual("1582-10-15", Lunar.fromYmd(1582, 9, 19).getSolar().toYmd()) 244 | 245 | def test59(self): 246 | self.assertEqual("1518-02-10", Lunar.fromYmd(1518, 1, 1).getSolar().toYmd()) 247 | 248 | def test60(self): 249 | self.assertEqual("0793-02-15", Lunar.fromYmd(793, 1, 1).getSolar().toYmd()) 250 | 251 | def test61(self): 252 | self.assertEqual("2025-07-25", Lunar.fromYmd(2025, -6, 1).getSolar().toYmd()) 253 | 254 | def test62(self): 255 | self.assertEqual("2025-06-25", Lunar.fromYmd(2025, 6, 1).getSolar().toYmd()) 256 | 257 | def test63(self): 258 | self.assertEqual("0193-02-19", Lunar.fromYmd(193, 1, 1).getSolar().toYmd()) 259 | 260 | def test64(self): 261 | self.assertEqual("0041-02-20", Lunar.fromYmd(41, 1, 1).getSolar().toYmd()) 262 | 263 | def test65(self): 264 | self.assertEqual("0554-02-18", Lunar.fromYmd(554, 1, 1).getSolar().toYmd()) 265 | 266 | def test66(self): 267 | self.assertEqual("1070-02-14", Lunar.fromYmd(1070, 1, 1).getSolar().toYmd()) 268 | 269 | def test67(self): 270 | self.assertEqual("1537-02-10", Lunar.fromYmd(1537, 1, 1).getSolar().toYmd()) 271 | 272 | def test68(self): 273 | self.assertEqual("九一七年闰十月十四", Solar.fromYmd(917, 12, 1).getLunar().toString()) 274 | 275 | def test69(self): 276 | self.assertEqual("九一七年冬月十五", Solar.fromYmd(917, 12, 31).getLunar().toString()) 277 | 278 | def test70(self): 279 | self.assertEqual("九一七年冬月十六", Solar.fromYmd(918, 1, 1).getLunar().toString()) 280 | -------------------------------------------------------------------------------- /test/NineStarTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import Solar, Lunar 4 | 5 | 6 | class NineStarTest(unittest.TestCase): 7 | 8 | def test1(self): 9 | lunar = Solar.fromYmd(1985, 2, 19).getLunar() 10 | self.assertEqual("六", lunar.getYearNineStar().getNumber()) 11 | 12 | def test23(self): 13 | lunar = Lunar.fromYmd(2022, 1, 1) 14 | self.assertEqual('六白金开阳', lunar.getYearNineStar().toString()) 15 | 16 | def test24(self): 17 | lunar = Lunar.fromYmd(2033, 1, 1) 18 | self.assertEqual('四绿木天权', lunar.getYearNineStar().toString()) 19 | -------------------------------------------------------------------------------- /test/ShuJiuTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import Solar 4 | 5 | 6 | class ShuJiuTest(unittest.TestCase): 7 | 8 | def test1(self): 9 | solar = Solar.fromYmd(2020, 12, 21) 10 | lunar = solar.getLunar() 11 | shu_jiu = lunar.getShuJiu() 12 | self.assertEqual("一九", shu_jiu.toString()) 13 | self.assertEqual("一九第1天", shu_jiu.toFullString()) 14 | 15 | def test2(self): 16 | solar = Solar.fromYmd(2020, 12, 22) 17 | lunar = solar.getLunar() 18 | shu_jiu = lunar.getShuJiu() 19 | self.assertEqual("一九", shu_jiu.toString()) 20 | self.assertEqual("一九第2天", shu_jiu.toFullString()) 21 | 22 | def test3(self): 23 | solar = Solar.fromYmd(2020, 1, 7) 24 | lunar = solar.getLunar() 25 | shu_jiu = lunar.getShuJiu() 26 | self.assertEqual("二九", shu_jiu.toString()) 27 | self.assertEqual("二九第8天", shu_jiu.toFullString()) 28 | 29 | def test4(self): 30 | solar = Solar.fromYmd(2021, 1, 6) 31 | lunar = solar.getLunar() 32 | shu_jiu = lunar.getShuJiu() 33 | self.assertEqual("二九", shu_jiu.toString()) 34 | self.assertEqual("二九第8天", shu_jiu.toFullString()) 35 | 36 | def test5(self): 37 | solar = Solar.fromYmd(2021, 1, 8) 38 | lunar = solar.getLunar() 39 | shu_jiu = lunar.getShuJiu() 40 | self.assertEqual("三九", shu_jiu.toString()) 41 | self.assertEqual("三九第1天", shu_jiu.toFullString()) 42 | 43 | def test6(self): 44 | solar = Solar.fromYmd(2021, 3, 5) 45 | lunar = solar.getLunar() 46 | shu_jiu = lunar.getShuJiu() 47 | self.assertEqual("九九", shu_jiu.toString()) 48 | self.assertEqual("九九第3天", shu_jiu.toFullString()) 49 | 50 | def test7(self): 51 | solar = Solar.fromYmd(2021, 7, 5) 52 | lunar = solar.getLunar() 53 | shu_jiu = lunar.getShuJiu() 54 | self.assertIsNone(shu_jiu) 55 | -------------------------------------------------------------------------------- /test/SolarMonthTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import SolarMonth 4 | 5 | 6 | class SolarMonthTest(unittest.TestCase): 7 | 8 | def test(self): 9 | month = SolarMonth.fromYm(2019, 5) 10 | self.assertEqual("2019-5", month.toString()) 11 | self.assertEqual("2019年5月", month.toFullString()) 12 | self.assertEqual("2019-6", month.next(1).toString()) 13 | self.assertEqual("2019年6月", month.next(1).toFullString()) 14 | -------------------------------------------------------------------------------- /test/SolarSeasonTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import SolarSeason 4 | 5 | 6 | class SolarSeasonTest(unittest.TestCase): 7 | 8 | def test(self): 9 | season = SolarSeason.fromYm(2019, 5) 10 | self.assertEqual("2019.2", season.toString()) 11 | self.assertEqual("2019年2季度", season.toFullString()) 12 | self.assertEqual("2019.3", season.next(1).toString()) 13 | self.assertEqual("2019年3季度", season.next(1).toFullString()) 14 | -------------------------------------------------------------------------------- /test/SolarTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from lunar_python import Solar 5 | from lunar_python.util import SolarUtil 6 | 7 | 8 | class SolarTest(unittest.TestCase): 9 | def test(self): 10 | solar = Solar.fromYmd(2019, 5, 1) 11 | self.assertEqual("2019-05-01", solar.toString()) 12 | self.assertEqual("2019-05-01 00:00:00 星期三 (劳动节) 金牛座", solar.toFullString()) 13 | self.assertEqual("二〇一九年三月廿七", solar.getLunar().toString()) 14 | self.assertEqual("二〇一九年三月廿七 己亥(猪)年 戊辰(龙)月 戊戌(狗)日 子(鼠)时 纳音[平地木 大林木 平地木 桑柘木] 星期三 西方白虎 星宿[参水猿](吉) 彭祖百忌[戊不受田田主不祥 戌不吃犬作怪上床] 喜神方位[巽](东南) 阳贵神方位[艮](东北) 阴贵神方位[坤](西南) 福神方位[艮](东北) 财神方位[坎](正北) 冲[(壬辰)龙] 煞[北]", solar.getLunar().toFullString()) 15 | 16 | def test1(self): 17 | solar = Solar.fromYmdHms(2020, 5, 24, 13, 0, 0) 18 | self.assertEqual("二〇二〇年闰四月初二", solar.getLunar().toString()) 19 | 20 | def test2(self): 21 | solar = Solar.fromYmd(11, 1, 1) 22 | self.assertEqual("一〇年腊月初八", solar.getLunar().toString()) 23 | 24 | def test3(self): 25 | solar = Solar.fromYmd(11, 3, 1) 26 | self.assertEqual("一一年二月初八", solar.getLunar().toString()) 27 | 28 | def test4(self): 29 | solar = Solar.fromYmd(26, 4, 13) 30 | self.assertEqual("二六年三月初八", solar.getLunar().toString()) 31 | 32 | def test6(self): 33 | solar = Solar.fromYmd(1, 1, 1) 34 | self.assertEqual("0001-01-01", solar.toString()) 35 | 36 | def test5(self): 37 | date = Solar.fromYmd(2020, 1, 23) 38 | self.assertEqual("2020-01-24", date.next(1).toString()) 39 | # 仅工作日,跨越春节假期 40 | self.assertEqual("2020-02-03", date.next(1, True).toString()) 41 | 42 | date = Solar.fromYmd(2020, 2, 3) 43 | self.assertEqual("2020-01-31", date.next(-3).toString()) 44 | # 仅工作日,跨越春节假期 45 | self.assertEqual("2020-01-21", date.next(-3, True).toString()) 46 | 47 | date = Solar.fromYmd(2020, 2, 9) 48 | self.assertEqual("2020-02-15", date.next(6).toString()) 49 | # 仅工作日,跨越周末 50 | self.assertEqual("2020-02-17", date.next(6, True).toString()) 51 | 52 | date = Solar.fromYmd(2020, 1, 17) 53 | self.assertEqual("2020-01-18", date.next(1).toString()) 54 | # 仅工作日,周日调休按上班算 55 | self.assertEqual("2020-01-19", date.next(1, True).toString()) 56 | 57 | def test10(self): 58 | self.assertEqual(True, SolarUtil.isLeapYear(1500)) 59 | 60 | def test11(self): 61 | solar = Solar.fromYmd(2022, 3, 28) 62 | self.assertEqual("全国中小学生安全教育日", solar.getFestivals()[0]) 63 | 64 | def test12(self): 65 | self.assertEqual("壬午", Solar.fromYmd(1991, 5, 12).getLunar().getDayInGanZhi()) 66 | 67 | def test13(self): 68 | self.assertEqual("1582-09-30", Solar.fromYmd(1582, 10, 15).next(-5).toYmd()) 69 | 70 | def test14(self): 71 | self.assertEqual("1582-10-04", Solar.fromYmd(1582, 10, 15).next(-1).toYmd()) 72 | 73 | def test15(self): 74 | self.assertEqual("1582-09-29", Solar.fromYmd(1582, 10, 15).next(-6).toYmd()) 75 | 76 | def test16(self): 77 | self.assertEqual(2, SolarUtil.getDaysBetween(100, 2, 28, 100, 3, 1)) 78 | 79 | def test17(self): 80 | self.assertEqual(59, SolarUtil.getDaysInYear(100, 2, 28)) 81 | 82 | def test18(self): 83 | self.assertEqual(61, SolarUtil.getDaysInYear(100, 3, 1)) 84 | 85 | def test19(self): 86 | self.assertEqual("2023-09-30", Solar.fromYmd(2023, 8, 31).nextMonth(1).toYmd()) 87 | 88 | def test20(self): 89 | self.assertEqual("2023-10-31", Solar.fromYmd(2023, 8, 31).nextMonth(2).toYmd()) 90 | 91 | def test21(self): 92 | self.assertEqual("2024-02-29", Solar.fromYmd(2023, 8, 31).nextMonth(6).toYmd()) 93 | 94 | def test22(self): 95 | self.assertEqual("2025-08-31", Solar.fromYmd(2023, 8, 31).nextYear(2).toYmd()) 96 | -------------------------------------------------------------------------------- /test/SolarWeekTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import SolarMonth 4 | 5 | 6 | class SolarWeekTest(unittest.TestCase): 7 | 8 | def test(self): 9 | month = SolarMonth.fromYm(2022, 12) 10 | self.assertEqual(5, len(month.getWeeks(0))) 11 | -------------------------------------------------------------------------------- /test/SolarYearTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import SolarYear 4 | 5 | 6 | class SolarYearTest(unittest.TestCase): 7 | def test(self): 8 | year = SolarYear.fromYear(2019) 9 | self.assertEqual("2019", year.toString()) 10 | self.assertEqual("2019年", year.toFullString()) 11 | 12 | self.assertEqual("2020", year.next(1).toString()) 13 | self.assertEqual("2020年", year.next(1).toFullString()) 14 | -------------------------------------------------------------------------------- /test/TaoTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import Tao, Lunar 4 | 5 | 6 | class TaoTest(unittest.TestCase): 7 | def test(self): 8 | tao = Tao.fromLunar(Lunar.fromYmdHms(2021, 10, 17, 18, 0, 0)) 9 | self.assertEqual("四七一八年十月十七", tao.toString()) 10 | self.assertEqual("道歷四七一八年,天运辛丑年,己亥月,癸酉日。十月十七日,酉時。", tao.toFullString()) 11 | 12 | def test1(self): 13 | tao = Tao.fromYmd(4718, 10, 18) 14 | self.assertEqual("地母娘娘圣诞", tao.getFestivals()[0].toString()) 15 | 16 | tao = Lunar.fromYmd(2021, 10, 18).getTao() 17 | self.assertEqual("四时会", tao.getFestivals()[1].toString()) 18 | -------------------------------------------------------------------------------- /test/WeekTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import SolarWeek, Solar 4 | from lunar_python.util import SolarUtil 5 | 6 | 7 | class WeekTest(unittest.TestCase): 8 | def test(self): 9 | # 一周的开始从星期一开始计 10 | start = 1 11 | week = SolarWeek.fromYmd(2019, 5, 1, start) 12 | self.assertEqual("2019.5.1", week.toString()) 13 | self.assertEqual("2019年5月第1周", week.toFullString()) 14 | # 当月共几周 15 | self.assertEqual(5, SolarUtil.getWeeksOfMonth(week.getYear(), week.getMonth(), start)) 16 | # 当周第一天 17 | self.assertEqual("2019-04-29", week.getFirstDay().toString()) 18 | # 当周第一天(本月) 19 | self.assertEqual("2019-05-01", week.getFirstDayInMonth().toString()) 20 | 21 | def test1(self): 22 | # 一周的开始从星期日开始计 23 | start = 0 24 | week = SolarWeek.fromYmd(2019, 5, 1, start) 25 | self.assertEqual("2019.5.1", week.toString()) 26 | self.assertEqual("2019年5月第1周", week.toFullString()) 27 | # 当月共几周 28 | self.assertEqual(5, SolarUtil.getWeeksOfMonth(week.getYear(), week.getMonth(), start)) 29 | # 当周第一天 30 | self.assertEqual("2019-04-28", week.getFirstDay().toString()) 31 | # 当周第一天(本月) 32 | self.assertEqual("2019-05-01", week.getFirstDayInMonth().toString()) 33 | 34 | def test2(self): 35 | week = SolarWeek.fromYmd(2022, 5, 1, 0) 36 | self.assertEqual(1, week.getIndex()) 37 | 38 | def test3(self): 39 | week = SolarWeek.fromYmd(2022, 5, 7, 0) 40 | self.assertEqual(1, week.getIndex()) 41 | 42 | def test4(self): 43 | week = SolarWeek.fromYmd(2022, 5, 8, 0) 44 | self.assertEqual(2, week.getIndex()) 45 | 46 | def test5(self): 47 | week = SolarWeek.fromYmd(2022, 5, 1, 1) 48 | self.assertEqual(1, week.getIndex()) 49 | 50 | def test6(self): 51 | week = SolarWeek.fromYmd(2022, 5, 2, 1) 52 | self.assertEqual(2, week.getIndex()) 53 | 54 | def test7(self): 55 | week = SolarWeek.fromYmd(2022, 5, 8, 1) 56 | self.assertEqual(2, week.getIndex()) 57 | 58 | def test8(self): 59 | week = SolarWeek.fromYmd(2021, 11, 1, 0) 60 | self.assertEqual(1, week.getIndex()) 61 | 62 | def test9(self): 63 | week = SolarWeek.fromYmd(2021, 11, 1, 1) 64 | self.assertEqual(1, week.getIndex()) 65 | 66 | def test10(self): 67 | week = SolarWeek.fromYmd(2021, 5, 2, 2) 68 | self.assertEqual(1, week.getIndex()) 69 | 70 | def test11(self): 71 | week = SolarWeek.fromYmd(2021, 5, 4, 2) 72 | self.assertEqual(2, week.getIndex()) 73 | 74 | def test12(self): 75 | week = SolarWeek.fromYmd(2022, 3, 6, 0) 76 | self.assertEqual(11, week.getIndexInYear()) 77 | 78 | def test13(self): 79 | self.assertEqual(1, Solar.fromYmd(1582, 10, 1).getWeek()) 80 | 81 | def test14(self): 82 | self.assertEqual(5, Solar.fromYmd(1582, 10, 15).getWeek()) 83 | 84 | def test15(self): 85 | self.assertEqual(0, Solar.fromYmd(1129, 11, 17).getWeek()) 86 | 87 | def test16(self): 88 | self.assertEqual(5, Solar.fromYmd(1129, 11, 1).getWeek()) 89 | 90 | def test17(self): 91 | self.assertEqual(4, Solar.fromYmd(8, 11, 1).getWeek()) 92 | 93 | def test18(self): 94 | self.assertEqual(0, Solar.fromYmd(1582, 9, 30).getWeek()) 95 | 96 | def test19(self): 97 | self.assertEqual(1, Solar.fromYmd(1582, 1, 1).getWeek()) 98 | 99 | def test20(self): 100 | self.assertEqual(6, Solar.fromYmd(1500, 2, 29).getWeek()) 101 | 102 | def test21(self): 103 | self.assertEqual(3, Solar.fromYmd(9865, 7, 26).getWeek()) 104 | 105 | def test22(self): 106 | self.assertEqual(6, Solar.fromYmd(1961, 9, 30).getWeek()) 107 | self.assertEqual(6, Solar.fromYmdHms(1961, 9, 30, 0, 0, 0).getWeek()) 108 | self.assertEqual(6, Solar.fromYmdHms(1961, 9, 30, 23, 59, 59).getWeek()) 109 | 110 | def test23(self): 111 | self.assertEqual(3, Solar.fromYmd(2021, 9, 15).getWeek()) 112 | self.assertEqual(3, Solar.fromYmdHms(2021, 9, 15, 0, 0, 0).getWeek()) 113 | self.assertEqual(3, Solar.fromYmdHms(2021, 9, 15, 23, 59, 59).getWeek()) 114 | -------------------------------------------------------------------------------- /test/WuHouTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from lunar_python import Solar 5 | 6 | 7 | class WuHouTest(unittest.TestCase): 8 | 9 | def test1(self): 10 | solar = Solar.fromYmd(2020, 4, 23) 11 | lunar = solar.getLunar() 12 | self.assertEqual("萍始生", lunar.getWuHou()) 13 | 14 | def test2(self): 15 | solar = Solar.fromYmd(2021, 1, 15) 16 | lunar = solar.getLunar() 17 | self.assertEqual("雉始雊", lunar.getWuHou()) 18 | 19 | def test3(self): 20 | solar = Solar.fromYmd(2017, 1, 5) 21 | lunar = solar.getLunar() 22 | self.assertEqual("雁北乡", lunar.getWuHou()) 23 | 24 | def test4(self): 25 | solar = Solar.fromYmd(2020, 4, 10) 26 | lunar = solar.getLunar() 27 | self.assertEqual("田鼠化为鴽", lunar.getWuHou()) 28 | 29 | def test5(self): 30 | solar = Solar.fromYmd(2020, 6, 11) 31 | lunar = solar.getLunar() 32 | self.assertEqual("鵙始鸣", lunar.getWuHou()) 33 | 34 | def test6(self): 35 | solar = Solar.fromYmd(2020, 6, 1) 36 | lunar = solar.getLunar() 37 | self.assertEqual("麦秋至", lunar.getWuHou()) 38 | 39 | def test7(self): 40 | solar = Solar.fromYmd(2020, 12, 8) 41 | lunar = solar.getLunar() 42 | self.assertEqual("鹖鴠不鸣", lunar.getWuHou()) 43 | 44 | def test8(self): 45 | solar = Solar.fromYmd(2020, 12, 11) 46 | lunar = solar.getLunar() 47 | self.assertEqual("鹖鴠不鸣", lunar.getWuHou()) 48 | 49 | def test9(self): 50 | solar = Solar.fromYmd(1982, 12, 22) 51 | lunar = solar.getLunar() 52 | self.assertEqual("蚯蚓结", lunar.getWuHou()) 53 | 54 | def test10(self): 55 | solar = Solar.fromYmd(2021, 12, 21) 56 | lunar = solar.getLunar() 57 | self.assertEqual("冬至 初候", lunar.getHou()) 58 | 59 | def test11(self): 60 | solar = Solar.fromYmd(2021, 12, 26) 61 | lunar = solar.getLunar() 62 | self.assertEqual("冬至 二候", lunar.getHou()) 63 | 64 | def test12(self): 65 | solar = Solar.fromYmd(2021, 12, 31) 66 | lunar = solar.getLunar() 67 | self.assertEqual("冬至 三候", lunar.getHou()) 68 | 69 | def test13(self): 70 | solar = Solar.fromYmd(2022, 1, 5) 71 | lunar = solar.getLunar() 72 | self.assertEqual("小寒 初候", lunar.getHou()) 73 | 74 | def test15(self): 75 | solar = Solar.fromYmd(2022, 8, 22) 76 | lunar = solar.getLunar() 77 | self.assertEqual("寒蝉鸣", lunar.getWuHou()) 78 | 79 | def test16(self): 80 | solar = Solar.fromYmd(2022, 8, 23) 81 | lunar = solar.getLunar() 82 | self.assertEqual("鹰乃祭鸟", lunar.getWuHou()) 83 | -------------------------------------------------------------------------------- /test/XingZuoTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import Solar 4 | 5 | 6 | class XingZuoTest(unittest.TestCase): 7 | 8 | def test1(self): 9 | solar = Solar.fromYmd(2020, 3, 21) 10 | self.assertEqual("白羊", solar.getXingZuo()) 11 | solar = Solar.fromYmd(2020, 4, 19) 12 | self.assertEqual("白羊", solar.getXingZuo()) 13 | 14 | def test2(self): 15 | solar = Solar.fromYmd(2020, 4, 20) 16 | self.assertEqual("金牛", solar.getXingZuo()) 17 | solar = Solar.fromYmd(2020, 5, 20) 18 | self.assertEqual("金牛", solar.getXingZuo()) 19 | 20 | def test3(self): 21 | solar = Solar.fromYmd(2020, 5, 21) 22 | self.assertEqual("双子", solar.getXingZuo()) 23 | solar = Solar.fromYmd(2020, 6, 21) 24 | self.assertEqual("双子", solar.getXingZuo()) 25 | 26 | def test4(self): 27 | solar = Solar.fromYmd(2020, 6, 22) 28 | self.assertEqual("巨蟹", solar.getXingZuo()) 29 | solar = Solar.fromYmd(2020, 7, 22) 30 | self.assertEqual("巨蟹", solar.getXingZuo()) 31 | 32 | def test5(self): 33 | solar = Solar.fromYmd(2020, 7, 23) 34 | self.assertEqual("狮子", solar.getXingZuo()) 35 | solar = Solar.fromYmd(2020, 8, 22) 36 | self.assertEqual("狮子", solar.getXingZuo()) 37 | 38 | def test6(self): 39 | solar = Solar.fromYmd(2020, 8, 23) 40 | self.assertEqual("处女", solar.getXingZuo()) 41 | solar = Solar.fromYmd(2020, 9, 22) 42 | self.assertEqual("处女", solar.getXingZuo()) 43 | 44 | def test7(self): 45 | solar = Solar.fromYmd(2020, 9, 23) 46 | self.assertEqual("天秤", solar.getXingZuo()) 47 | solar = Solar.fromYmd(2020, 10, 23) 48 | self.assertEqual("天秤", solar.getXingZuo()) 49 | 50 | def test8(self): 51 | solar = Solar.fromYmd(2020, 10, 24) 52 | self.assertEqual("天蝎", solar.getXingZuo()) 53 | solar = Solar.fromYmd(2020, 11, 22) 54 | self.assertEqual("天蝎", solar.getXingZuo()) 55 | 56 | def test9(self): 57 | solar = Solar.fromYmd(2020, 11, 23) 58 | self.assertEqual("射手", solar.getXingZuo()) 59 | solar = Solar.fromYmd(2020, 12, 21) 60 | self.assertEqual("射手", solar.getXingZuo()) 61 | 62 | def test10(self): 63 | solar = Solar.fromYmd(2020, 12, 22) 64 | self.assertEqual("摩羯", solar.getXingZuo()) 65 | solar = Solar.fromYmd(2021, 1, 19) 66 | self.assertEqual("摩羯", solar.getXingZuo()) 67 | 68 | def test11(self): 69 | solar = Solar.fromYmd(2021, 1, 20) 70 | self.assertEqual("水瓶", solar.getXingZuo()) 71 | solar = Solar.fromYmd(2021, 2, 18) 72 | self.assertEqual("水瓶", solar.getXingZuo()) 73 | 74 | def test12(self): 75 | solar = Solar.fromYmd(2021, 2, 19) 76 | self.assertEqual("双鱼", solar.getXingZuo()) 77 | solar = Solar.fromYmd(2021, 3, 20) 78 | self.assertEqual("双鱼", solar.getXingZuo()) 79 | -------------------------------------------------------------------------------- /test/XunTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import Solar 4 | 5 | 6 | class XunTest(unittest.TestCase): 7 | def testXun1(self): 8 | solar = Solar.fromYmdHms(2020, 11, 19, 0, 0, 0) 9 | lunar = solar.getLunar() 10 | self.assertEqual("甲午", lunar.getYearXun()) 11 | 12 | def testXunKong1(self): 13 | solar = Solar.fromYmdHms(2020, 11, 19, 0, 0, 0) 14 | lunar = solar.getLunar() 15 | self.assertEqual("辰巳", lunar.getYearXunKong()) 16 | self.assertEqual("午未", lunar.getMonthXunKong()) 17 | self.assertEqual("戌亥", lunar.getDayXunKong()) 18 | 19 | def testXunAndKong(self): 20 | solar = Solar.fromYmd(2022, 5, 24) 21 | lunar = solar.getLunar() 22 | self.assertEqual("甲戌", lunar.getDayXun()) 23 | self.assertEqual("申酉", lunar.getDayXunKong()) 24 | 25 | def testBaZiDayXunKong(self): 26 | solar = Solar.fromYmdHms(1990, 12, 23, 8, 37, 0) 27 | lunar = solar.getLunar() 28 | eight_char = lunar.getEightChar() 29 | self.assertEqual("子丑", eight_char.getDayXunKong()) 30 | -------------------------------------------------------------------------------- /test/YearTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from lunar_python import LunarYear 5 | 6 | 7 | class YearTest(unittest.TestCase): 8 | 9 | def test1(self): 10 | year = LunarYear.fromYear(2017) 11 | self.assertEqual("二龙治水", year.getZhiShui()) 12 | self.assertEqual("二人分饼", year.getFenBing()) 13 | 14 | def test2(self): 15 | year = LunarYear.fromYear(2018) 16 | self.assertEqual("二龙治水", year.getZhiShui()) 17 | self.assertEqual("八人分饼", year.getFenBing()) 18 | 19 | def test3(self): 20 | year = LunarYear.fromYear(5) 21 | self.assertEqual("三龙治水", year.getZhiShui()) 22 | self.assertEqual("一人分饼", year.getFenBing()) 23 | 24 | def test4(self): 25 | year = LunarYear.fromYear(2021) 26 | self.assertEqual("十一牛耕田", year.getGengTian()) 27 | 28 | def test5(self): 29 | year = LunarYear.fromYear(2018) 30 | self.assertEqual("三日得金", year.getDeJin()) 31 | 32 | def test6(self): 33 | year = LunarYear.fromYear(1864) 34 | self.assertEqual("上元", year.getYuan()) 35 | 36 | def test7(self): 37 | year = LunarYear.fromYear(1923) 38 | self.assertEqual("上元", year.getYuan()) 39 | 40 | def test8(self): 41 | year = LunarYear.fromYear(1924) 42 | self.assertEqual("中元", year.getYuan()) 43 | 44 | def test9(self): 45 | year = LunarYear.fromYear(1983) 46 | self.assertEqual("中元", year.getYuan()) 47 | 48 | def test10(self): 49 | year = LunarYear.fromYear(1984) 50 | self.assertEqual("下元", year.getYuan()) 51 | 52 | def test11(self): 53 | year = LunarYear.fromYear(2043) 54 | self.assertEqual("下元", year.getYuan()) 55 | 56 | def test12(self): 57 | year = LunarYear.fromYear(1864) 58 | self.assertEqual("一运", year.getYun()) 59 | 60 | def test13(self): 61 | year = LunarYear.fromYear(1883) 62 | self.assertEqual("一运", year.getYun()) 63 | 64 | def test14(self): 65 | year = LunarYear.fromYear(1884) 66 | self.assertEqual("二运", year.getYun()) 67 | 68 | def test15(self): 69 | year = LunarYear.fromYear(1903) 70 | self.assertEqual("二运", year.getYun()) 71 | 72 | def test16(self): 73 | year = LunarYear.fromYear(1904) 74 | self.assertEqual("三运", year.getYun()) 75 | 76 | def test17(self): 77 | year = LunarYear.fromYear(1923) 78 | self.assertEqual("三运", year.getYun()) 79 | 80 | def test18(self): 81 | year = LunarYear.fromYear(2004) 82 | self.assertEqual("八运", year.getYun()) 83 | 84 | def test19(self): 85 | year = LunarYear.fromYear(2023) 86 | self.assertEqual(384, year.getDayCount()) 87 | 88 | def test20(self): 89 | year = LunarYear.fromYear(1517) 90 | self.assertEqual(384, year.getDayCount()) 91 | 92 | def test21(self): 93 | year = LunarYear.fromYear(1518) 94 | self.assertEqual(355, year.getDayCount()) 95 | 96 | def test22(self): 97 | year = LunarYear.fromYear(2021) 98 | self.assertEqual(354, year.getDayCount()) 99 | -------------------------------------------------------------------------------- /test/YunTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from lunar_python import Solar, Lunar 4 | 5 | 6 | class YunTest(unittest.TestCase): 7 | def test(self): 8 | solar = Solar.fromYmdHms(1981, 1, 29, 23, 37, 0) 9 | lunar = solar.getLunar() 10 | eight_char = lunar.getEightChar() 11 | yun = eight_char.getYun(0) 12 | self.assertEqual(8, yun.getStartYear(), "起运年数") 13 | self.assertEqual(0, yun.getStartMonth(), "起运月数") 14 | self.assertEqual(20, yun.getStartDay(), "起运天数") 15 | self.assertEqual("1989-02-18", yun.getStartSolar().toYmd(), "起运阳历") 16 | 17 | def test2(self): 18 | lunar = Lunar.fromYmdHms(2019, 12, 12, 11, 22, 0) 19 | eight_char = lunar.getEightChar() 20 | yun = eight_char.getYun(1) 21 | self.assertEqual(0, yun.getStartYear(), "起运年数") 22 | self.assertEqual(1, yun.getStartMonth(), "起运月数") 23 | self.assertEqual(0, yun.getStartDay(), "起运天数") 24 | self.assertEqual("2020-02-06", yun.getStartSolar().toYmd(), "起运阳历") 25 | 26 | def test3(self): 27 | solar = Solar.fromYmdHms(2020, 1, 6, 11, 22, 0) 28 | lunar = solar.getLunar() 29 | eight_char = lunar.getEightChar() 30 | yun = eight_char.getYun(1) 31 | self.assertEqual(0, yun.getStartYear(), "起运年数") 32 | self.assertEqual(1, yun.getStartMonth(), "起运月数") 33 | self.assertEqual(0, yun.getStartDay(), "起运天数") 34 | self.assertEqual("2020-02-06", yun.getStartSolar().toYmd(), "起运阳历") 35 | 36 | def test4(self): 37 | solar = Solar.fromYmdHms(2022, 3, 9, 20, 51, 0) 38 | lunar = solar.getLunar() 39 | eight_char = lunar.getEightChar() 40 | yun = eight_char.getYun(1) 41 | self.assertEqual("2030-12-19", yun.getStartSolar().toYmd(), "起运阳历") 42 | 43 | def test5(self): 44 | solar = Solar.fromYmdHms(2022, 3, 9, 20, 51, 0) 45 | lunar = solar.getLunar() 46 | eight_char = lunar.getEightChar() 47 | yun = eight_char.getYun(1, 2) 48 | self.assertEqual(8, yun.getStartYear(), "起运年数") 49 | self.assertEqual(9, yun.getStartMonth(), "起运月数") 50 | self.assertEqual(2, yun.getStartDay(), "起运天数") 51 | self.assertEqual("2030-12-12", yun.getStartSolar().toYmd(), "起运阳历") 52 | 53 | def test6(self): 54 | solar = Solar.fromYmdHms(2018, 6, 11, 9, 30, 0) 55 | lunar = solar.getLunar() 56 | eight_char = lunar.getEightChar() 57 | yun = eight_char.getYun(0, 2) 58 | self.assertEqual("2020-03-21", yun.getStartSolar().toYmd(), "起运阳历") 59 | --------------------------------------------------------------------------------