From 09d6fdb284bbd44153aa385563682e216d83de35 Mon Sep 17 00:00:00 2001 From: kinegratii Date: Fri, 29 Mar 2024 21:38:32 +0800 Subject: [PATCH] :sparkles: New LunarDate for last day in a year --- borax/calendars/festivals2.py | 10 ++++++---- borax/calendars/lunardate.py | 8 +++++++- docs/changelog.md | 2 ++ tests/test_festival2_list.py | 8 ++++++++ tests/test_lunardate.py | 2 ++ 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/borax/calendars/festivals2.py b/borax/calendars/festivals2.py index 49f0ccd..de999a4 100644 --- a/borax/calendars/festivals2.py +++ b/borax/calendars/festivals2.py @@ -169,8 +169,9 @@ class Period: """A shortcut methods for some specified date Period.""" @staticmethod - def solar_year(year: int) -> Tuple[date, date]: - return date(year, 1, 1), date(year, 12, 31) + def solar_year(year: int, end_year: int = 0) -> Tuple[date, date]: + end_year = end_year or year + return date(year, 1, 1), date(end_year, 12, 31) @staticmethod def solar_month(year: int, month: int) -> Tuple[date, date]: @@ -178,8 +179,9 @@ def solar_month(year: int, month: int) -> Tuple[date, date]: return date(year, month, 1), date(year, month, ndays) @staticmethod - def lunar_year(year: int) -> Tuple[LunarDate, LunarDate]: - return LunarDate(year, 1, 1), LunarDate(year + 1, 1, 1) - timedelta(days=1) + def lunar_year(year: int, end_year: int = 0) -> Tuple[LunarDate, LunarDate]: + end_year = end_year or year + return LunarDate(year, 1, 1), LunarDate.last_day_of_year(end_year) @staticmethod def lunar_month(year: int, month: int, leap: int = _IGNORE_LEAP_MONTH) -> Tuple[LunarDate, LunarDate]: diff --git a/borax/calendars/lunardate.py b/borax/calendars/lunardate.py index c00591d..8250037 100644 --- a/borax/calendars/lunardate.py +++ b/borax/calendars/lunardate.py @@ -658,6 +658,12 @@ def tomorrow(cls) -> 'LunarDate': sd = datetime.date.today() + datetime.timedelta(days=1) return cls.from_solar_date(sd.year, sd.month, sd.day) + @classmethod + def last_day_of_year(cls, year: int) -> 'LunarDate': + """return the last day in a lunar year.""" + month, day, leap = list(LCalendars.iter_year_month(year))[-1] + return cls(year, month, day, leap) + @classmethod def strptime(cls, date_str: str, date_fmt: str) -> 'LunarDate': """Parse a LunarDate object from a whole string. @@ -678,7 +684,7 @@ def __sub__(self, other): :param other: a instance of LunarDate / date / timedelta :return: """ - if hasattr(other, 'solar'): + if hasattr(other, 'solar'): # For WrappedDate in festivals2 module return self.to_solar_date() - other.solar elif isinstance(other, LunarDate): return self.to_solar_date() - other.to_solar_date() diff --git a/docs/changelog.md b/docs/changelog.md index 0de0594..06b76fa 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,7 +2,9 @@ ## v4.1.1 +- 新增创建农历年最后一天的方法 `LunarDate.last_day_of_year` - `SolarFestival` 和`LunarFestival` 初始化函数 `freq` 参数支持字符串设置( [ #56](https://github.com/kinegratii/borax/issues/56) ) +- `Period.solar_year` 和 `Period.lunar_year` 新增 `end_year` 参数,支持跨年份计算 ## v4.1.0 (20240131) diff --git a/tests/test_festival2_list.py b/tests/test_festival2_list.py index 5d46530..fd2b9a3 100644 --- a/tests/test_festival2_list.py +++ b/tests/test_festival2_list.py @@ -167,6 +167,10 @@ def test_solar_period(self): self.assertEqual(date(2020, 5, 1), sd2) self.assertEqual(date(2020, 5, 31), ed2) + sd3, ed3 = Period.solar_year(2020, 2021) + self.assertEqual(date(2020, 1, 1), sd3) + self.assertEqual(date(2021, 12, 31), ed3) + def test_lunar_period(self): sd1, ed1 = Period.lunar_year(2020) self.assertEqual(LunarDate(2020, 1, 1), sd1) @@ -188,6 +192,10 @@ def test_lunar_period(self): self.assertEqual(LunarDate(2020, 5, 1, 0), sd5) self.assertEqual(LunarDate(2020, 5, 30, 0), ed5) + sd6, ed6 = Period.lunar_year(2020, 2021) + self.assertEqual(LunarDate(2020, 1, 1), sd6) + self.assertEqual(LunarDate(2021, 12, 29), ed6) + class WrappedDateTestCase(unittest.TestCase): diff --git a/tests/test_lunardate.py b/tests/test_lunardate.py index 6bfc51e..1ae8465 100644 --- a/tests/test_lunardate.py +++ b/tests/test_lunardate.py @@ -37,6 +37,8 @@ def test_create_specific_dates(self): self.assertEqual(5, LCalendars.delta(today.after(5), today)) self.assertEqual(-5, LCalendars.delta(today.before(5), today)) + self.assertEqual(LunarDate(2023, 12, 30), LunarDate.last_day_of_year(2023)) + def test_convert_datetime(self): dt = LunarDate(1976, 8, 8, 1).to_solar_date() self.assertEqual(date(1976, 10, 1), dt)