Files
moxiaonian d9da4301cd 公众授权版:normal · 1000 次 · 有效期至 2026-12-31
副本编号 LY-20261007-AC63(水印指纹已嵌入)
含 README、.gitignore;排除 .DS_Store / __pycache__ / .pytest_cache
2026-10-07 17:29:52 +08:00

206 lines
7.4 KiB
Python

# -*- coding:utf-8 -*-
from __future__ import annotations
from abc import abstractmethod
from typing import TYPE_CHECKING, List, Union
from tyme4py import AbstractTyme, Tyme
from tyme4py.enums import EventType
from tyme4py.event import Event
from tyme4py.unit import DayUnit
if TYPE_CHECKING:
from tyme4py.lunar import LunarDay
from tyme4py.solar import SolarTerm, SolarDay
class AbstractFestival(AbstractTyme):
@abstractmethod
def next(self, n: int) -> Union[Tyme, None]:
pass
def __init__(self, index: int, event: Event, day: DayUnit):
self._index = index
self._event = event
self._day = day
def get_name(self) -> str:
return self._event.get_name()
def get_index(self) -> int:
"""
:return: 索引
"""
return self._index
def get_day(self) -> DayUnit:
"""
:return: 日
"""
return self._day
def __str__(self) -> str:
return f'{self._day} {self.get_name()}'
class LunarFestival(AbstractFestival):
"""
农历传统节日--依据国家标准《农历的编算和颁行》GB/T 33661-2017
农历传统节日有:春节、元宵节、龙头节、上巳节、清明节、端午节、七夕节、中元节、中秋节、重阳节、冬至节、腊八节、除夕。
"""
NAMES: List[str] = ['春节', '元宵节', '龙头节', '上巳节', '清明节', '端午节', '七夕节', '中元节', '中秋节', '重阳节', '冬至节', '腊八节', '除夕']
"""名称"""
DATA: str = '2VV__0002Vj__0002WW__0002XX__0003b___0002ZZ__0002bb__0002bj__0002cj__0002dd__0003s___0002gc__0002hV_U000'
def __init__(self, index: int, event: Event, day: LunarDay):
"""
实例化
:param index: 索引
:param event: 事件
:param day: 农历日
"""
super().__init__(index, event, day)
@classmethod
def from_index(cls, year: int, index: int) -> Union[LunarFestival, None]:
"""
指定索引得到
:param year: 年
:param index: 索引
:return:
"""
if index < 0 or index >= cls.NAMES.__len__():
return None
from tyme4py.lunar import LunarDay
from tyme4py.solar import SolarTerm
start: int = index * 8
e: Event = Event(LunarFestival.NAMES[index], '@' + LunarFestival.DATA[start: start + 8])
t: EventType = e.get_type()
if t == EventType.LUNAR_DAY:
m: List[int] = e.get_month(year)
d: LunarDay = LunarDay.from_ymd(m[0], m[1], e.get_value(3))
offset: int = e.get_value(5)
return LunarFestival(index, e, d if offset == 0 else d.next(offset))
elif t == EventType.TERM_DAY:
return LunarFestival(index, e, SolarTerm.from_index(year, e.get_value(2)).get_solar_day().get_lunar_day())
return None
@classmethod
def from_ymd(cls, year: int, month: int, day: int) -> Union[LunarFestival, None]:
"""
指定农历年、月、日得到
:param year: 农历年
:param month: 农历月
:param day: 农历日
:return:
"""
from tyme4py.lunar import LunarDay
from tyme4py.solar import SolarTermDay
d: LunarDay = LunarDay.from_ymd(year, month, day)
for i in range(0, LunarFestival.NAMES.__len__()):
start: int = i * 8
e: Event = Event(LunarFestival.NAMES[i], '@' + LunarFestival.DATA[start: start + 8])
t: EventType = e.get_type()
if t == EventType.LUNAR_DAY:
offset: int = e.get_value(5)
if offset == 0:
if d.get_month() == e.get_value(2) and d.get_day() == e.get_value(3):
return LunarFestival(i, e, d)
else:
m: List[int] = e.get_month(d.get_year())
n: LunarDay = d.next(-offset)
if n.get_year() == m[0] and n.get_month() == m[1] and n.get_day() == e.get_value(3):
return LunarFestival(i, e, d)
elif t == EventType.TERM_DAY:
term: SolarTermDay = d.get_solar_day().get_term_day()
if term.get_day_index() == 0 and term.get_solar_term().get_index() == e.get_value(2) % 24:
return LunarFestival(i, e, d)
return None
def get_day(self) -> LunarDay:
"""
:return: 农历日
"""
return super().get_day()
def get_solar_term(self) -> Union[SolarTerm, None]:
"""
节气,非节气返回None
:return: 节气
"""
from tyme4py.solar import SolarTermDay
t: SolarTermDay = self.get_day().get_solar_day().get_term_day()
return t.get_solar_term() if t.get_day_index() == 0 else None
def next(self, n: int) -> LunarFestival:
size: int = LunarFestival.NAMES.__len__()
i: int = self._index + n
return LunarFestival.from_index(int((self._day.get_year() * size + i) / size), self.index_of(i, size))
class SolarFestival(AbstractFestival):
"""公历现代节日"""
NAMES: List[str] = ['元旦', '妇女节', '植树节', '劳动节', '青年节', '儿童节', '建党节', '建军节', '教师节', '国庆节']
DATA: str = '0VV__0Ux0Xc__0Ux0Xg__0_Q0ZV__0Ux0ZY__0Ux0aV__0Ux0bV__0Uo0cV__0Ug0de__0_V0eV__0Ux'
def __init__(self, index: int, event: Event, day: SolarDay):
"""
实例化
:param index: 索引
:param event: 事件
:param day: 公历日
"""
super().__init__(index, event, day)
@classmethod
def from_index(cls, year: int, index: int) -> Union[SolarFestival, None]:
"""
指定索引得到
:param year: 年份
:param index: 索引
:return:
"""
if index < 0 or index >= cls.NAMES.__len__():
return None
start: int = index * 8
e: Event = Event(SolarFestival.NAMES[index], '@' + SolarFestival.DATA[start: start + 8])
if year < e.get_start_year():
return None
from tyme4py.solar import SolarDay
return SolarFestival(index, e, SolarDay.from_ymd(year, e.get_value(2), e.get_value(3)))
@classmethod
def from_ymd(cls, year: int, month: int, day: int) -> Union[SolarFestival, None]:
"""
指定年、月、日得到
:param year: 年
:param month: 月
:param day: 日
:return:
"""
from tyme4py.solar import SolarDay
d: SolarDay = SolarDay.from_ymd(year, month, day)
for i in range(0, SolarFestival.NAMES.__len__()):
start: int = i * 8
e: Event = Event(SolarFestival.NAMES[i], '@' + SolarFestival.DATA[start: start + 8])
if d.get_year() >= e.get_start_year() and d.get_month() == e.get_value(2) and d.get_day() == e.get_value(3):
return SolarFestival(i, e, d)
return None
def get_day(self) -> SolarDay:
"""
:return: 公历日
"""
return super().get_day()
def get_start_year(self) -> int:
"""
起始年
:return: 年
"""
return self._event.get_start_year()
def next(self, n: int) -> Union[SolarFestival, None]:
size: int = SolarFestival.NAMES.__len__()
i: int = self._index + n
return SolarFestival.from_index(int((self._day.get_year() * size + i) / size), self.index_of(i, size))