staran 1.0.10__py3-none-any.whl → 1.0.11__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
staran/__init__.py CHANGED
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ Staran - 企业级Python日期处理库
6
+ """
7
+
8
+ __version__ = "1.0.11"
9
+ __author__ = "StarAn"
10
+ __email__ = "starlxa@icloud.com"
11
+ __license__ = "MIT"
12
+
13
+ # 导入核心功能
14
+ try:
15
+ from .date import (
16
+ Date,
17
+ DateRange,
18
+ DateError,
19
+ LunarDate,
20
+ Language,
21
+ today,
22
+ from_string,
23
+ from_lunar,
24
+ parse_expression,
25
+ get_version_info,
26
+ get_feature_status
27
+ )
28
+ except ImportError as e:
29
+ import warnings
30
+ warnings.warn(f"Staran核心功能导入失败: {e}")
31
+
32
+ Date = None
33
+ DateRange = None
34
+ DateError = Exception
35
+ LunarDate = None
36
+ Language = None
37
+
38
+ def today():
39
+ raise ImportError("Staran核心功能不可用")
40
+
41
+ def from_string(date_string: str):
42
+ raise ImportError("Staran核心功能不可用")
43
+
44
+ def from_lunar(year: int, month: int, day: int, is_leap: bool = False):
45
+ raise ImportError("Staran核心功能不可用")
46
+
47
+ def parse_expression(expression: str):
48
+ raise ImportError("Staran核心功能不可用")
49
+
50
+ def get_version_info():
51
+ return {'version': __version__, 'status': 'core_unavailable'}
52
+
53
+ def get_feature_status():
54
+ return {'core_available': False}
55
+
56
+ __all__ = [
57
+ '__version__', '__author__', '__email__', '__license__',
58
+ 'Date', 'DateRange', 'DateError', 'LunarDate', 'Language',
59
+ 'today', 'from_string', 'from_lunar', 'parse_expression',
60
+ 'get_version_info', 'get_feature_status'
61
+ ]
staran/date/__init__.py CHANGED
@@ -6,7 +6,7 @@ Staran 日期处理库 v1.0.10 - 简化版导入
6
6
  """
7
7
 
8
8
  # 版本信息
9
- __version__ = "1.0.10"
9
+ __version__ = "1.0.11"
10
10
  __author__ = "StarAn"
11
11
  __email__ = "starlxa@icloud.com"
12
12
 
staran/date/core/lunar.py CHANGED
@@ -8,9 +8,8 @@
8
8
  提供公历与农历互转功能,支持农历日期的创建、输出和比较。
9
9
  基于中国传统农历历法计算,支持1900-2100年范围。
10
10
  """
11
-
12
- import datetime
13
11
  from typing import Tuple, Optional, Union, TYPE_CHECKING
12
+ import datetime
14
13
 
15
14
  if TYPE_CHECKING:
16
15
  from .core import Date
@@ -23,7 +22,6 @@ class LunarDate:
23
22
  """
24
23
 
25
24
  # 农历数据表 (1900-2100年)
26
- # 每个数字的低12位表示12个月,第13位表示闰月月份,第14-17位表示闰月天数
27
25
  _LUNAR_INFO = [
28
26
  0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2,
29
27
  0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977,
@@ -48,63 +46,19 @@ class LunarDate:
48
46
  0x0d520
49
47
  ]
50
48
 
51
- # 农历月份名称
52
- _LUNAR_MONTHS = ['正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '冬', '腊']
53
- _LUNAR_DAYS = ['初一', '初二', '初三', '初四', '初五', '初六', '初七', '初八', '初九', '初十',
54
- '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十',
55
- '廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '三十']
56
-
57
- # 天干地支
58
- _TIANGAN = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']
59
- _DIZHI = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']
60
- _ZODIAC = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪']
61
-
62
49
  def __init__(self, year: int, month: int, day: int, is_leap: bool = False):
63
- """初始化农历日期
64
-
65
- Args:
66
- year: 农历年份
67
- month: 农历月份
68
- day: 农历日期
69
- is_leap: 是否闰月
70
- """
71
50
  self.year = year
72
51
  self.month = month
73
52
  self.day = day
74
53
  self.is_leap = is_leap
75
-
76
- if not self._is_valid():
77
- raise ValueError(f"无效的农历日期: {year}年{month}月{day}日")
78
-
79
- def _is_valid(self) -> bool:
80
- """验证农历日期是否有效"""
81
- if not (1900 <= self.year <= 2100):
82
- return False
83
- if not (1 <= self.month <= 12):
84
- return False
85
- if not (1 <= self.day <= 30):
86
- return False
87
- return True
88
54
 
89
55
  @classmethod
90
- def from_solar(cls, solar_date: Union[datetime.date, 'Date']) -> 'LunarDate':
91
- """从公历日期转换为农历日期
92
-
93
- Args:
94
- solar_date: 公历日期对象
95
-
96
- Returns:
97
- 农历日期对象
98
- """
56
+ def from_solar(cls, solar_date):
57
+ """从公历日期转换为农历日期"""
99
58
  if hasattr(solar_date, 'to_datetime_object'):
100
- # 处理自定义Date对象
101
59
  solar_date = solar_date.to_datetime_object()
102
60
 
103
- year = solar_date.year
104
- month = solar_date.month
105
- day = solar_date.day
106
-
107
- # 计算距离1900年1月31日(农历1900年正月初一)的天数
61
+ # 计算距离1900年1月31日的天数
108
62
  base_date = datetime.date(1900, 1, 31)
109
63
  delta = solar_date - base_date
110
64
  offset = delta.days
@@ -130,7 +84,6 @@ class LunarDate:
130
84
  if offset >= month_days:
131
85
  offset -= month_days
132
86
  if lunar_month == leap_month and not is_leap:
133
- # 处理闰月
134
87
  leap_days = cls._get_lunar_month_days(lunar_year, lunar_month, True)
135
88
  if offset >= leap_days:
136
89
  offset -= leap_days
@@ -144,43 +97,10 @@ class LunarDate:
144
97
  break
145
98
 
146
99
  lunar_day = offset + 1
147
-
148
100
  return cls(lunar_year, lunar_month, lunar_day, is_leap)
149
101
 
150
- def to_solar(self) -> datetime.date:
151
- """转换为公历日期
152
-
153
- Returns:
154
- 公历日期对象
155
- """
156
- # 计算农历日期距离1900年正月初一的天数
157
- offset = 0
158
-
159
- # 累加年份天数
160
- for year in range(1900, self.year):
161
- offset += self._get_lunar_year_days(year)
162
-
163
- # 累加月份天数
164
- for month in range(1, self.month):
165
- offset += self._get_lunar_month_days(self.year, month, False)
166
- # 如果有闰月且月份匹配,还要加上闰月天数
167
- leap_month = self._get_leap_month(self.year)
168
- if month == leap_month:
169
- offset += self._get_lunar_month_days(self.year, month, True)
170
-
171
- # 如果是闰月,还要加上正常月份的天数
172
- if self.is_leap:
173
- offset += self._get_lunar_month_days(self.year, self.month, False)
174
-
175
- # 加上日期天数
176
- offset += self.day - 1
177
-
178
- # 基准日期: 1900年1月31日(农历1900年正月初一)
179
- base_date = datetime.date(1900, 1, 31)
180
- return base_date + datetime.timedelta(days=offset)
181
-
182
102
  @classmethod
183
- def _get_lunar_year_days(cls, year: int) -> int:
103
+ def _get_lunar_year_days(cls, year):
184
104
  """获取农历年的总天数"""
185
105
  if year < 1900 or year > 2100:
186
106
  return 0
@@ -189,8 +109,8 @@ class LunarDate:
189
109
  days = 0
190
110
 
191
111
  # 12个月的天数
192
- for i in range(12):
193
- days += 29 if (info & (0x10000 >> i)) == 0 else 30
112
+ for month in range(1, 13):
113
+ days += 29 if (info & (0x10000 >> month)) == 0 else 30
194
114
 
195
115
  # 闰月天数
196
116
  leap_month = cls._get_leap_month(year)
@@ -200,7 +120,7 @@ class LunarDate:
200
120
  return days
201
121
 
202
122
  @classmethod
203
- def _get_lunar_month_days(cls, year: int, month: int, is_leap: bool = False) -> int:
123
+ def _get_lunar_month_days(cls, year, month, is_leap=False):
204
124
  """获取农历月的天数"""
205
125
  if year < 1900 or year > 2100:
206
126
  return 0
@@ -208,113 +128,23 @@ class LunarDate:
208
128
  info = cls._LUNAR_INFO[year - 1900]
209
129
 
210
130
  if is_leap:
211
- # 闰月天数
212
131
  leap_month = cls._get_leap_month(year)
213
132
  if month != leap_month:
214
133
  return 0
215
134
  return 29 if (info & 0x10000) == 0 else 30
216
135
  else:
217
- # 正常月份天数
218
136
  return 29 if (info & (0x10000 >> month)) == 0 else 30
219
137
 
220
138
  @classmethod
221
- def _get_leap_month(cls, year: int) -> int:
222
- """获取闰月月份,如果没有闰月返回0"""
139
+ def _get_leap_month(cls, year):
140
+ """获取闰月月份"""
223
141
  if year < 1900 or year > 2100:
224
142
  return 0
225
143
 
226
144
  info = cls._LUNAR_INFO[year - 1900]
227
145
  return info & 0xf
228
146
 
229
- def get_ganzhi_year(self) -> str:
230
- """获取天干地支年份"""
231
- # 甲子年为1984年,每60年一个周期
232
- offset = (self.year - 1984) % 60
233
- tiangan_index = offset % 10
234
- dizhi_index = offset % 12
235
- return self._TIANGAN[tiangan_index] + self._DIZHI[dizhi_index]
236
-
237
- def get_zodiac(self) -> str:
238
- """获取生肖"""
239
- return self._ZODIAC[(self.year - 1900) % 12]
240
-
241
- def format_chinese(self, include_year: bool = True, include_zodiac: bool = False) -> str:
242
- """格式化为中文农历日期
243
-
244
- Args:
245
- include_year: 是否包含年份
246
- include_zodiac: 是否包含生肖
247
-
248
- Returns:
249
- 中文农历日期字符串
250
- """
251
- result = ""
252
-
253
- if include_year:
254
- if include_zodiac:
255
- result += f"{self.get_ganzhi_year()}({self.get_zodiac()})年"
256
- else:
257
- result += f"农历{self.year}年"
258
-
259
- # 月份
260
- if self.is_leap:
261
- result += f"闰{self._LUNAR_MONTHS[self.month - 1]}月"
262
- else:
263
- result += f"{self._LUNAR_MONTHS[self.month - 1]}月"
264
-
265
- # 日期
266
- result += self._LUNAR_DAYS[self.day - 1]
267
-
268
- return result
269
-
270
- def format_compact(self) -> str:
271
- """紧凑格式"""
272
- leap_prefix = "闰" if self.is_leap else ""
273
- return f"{self.year}{leap_prefix}{self.month:02d}{self.day:02d}"
274
-
275
- def format_iso_like(self) -> str:
276
- """类ISO格式"""
277
- leap_suffix = "L" if self.is_leap else ""
278
- return f"{self.year}-{self.month:02d}{leap_suffix}-{self.day:02d}"
279
-
280
- def __str__(self) -> str:
281
- """字符串表示"""
282
- return self.format_chinese()
283
-
284
- def __repr__(self) -> str:
285
- """调试表示"""
286
- return f"LunarDate({self.year}, {self.month}, {self.day}, is_leap={self.is_leap})"
287
-
288
- def __eq__(self, other) -> bool:
289
- """相等比较"""
290
- if not isinstance(other, LunarDate):
291
- return False
292
- return (self.year == other.year and
293
- self.month == other.month and
294
- self.day == other.day and
295
- self.is_leap == other.is_leap)
296
-
297
- def __lt__(self, other) -> bool:
298
- """小于比较"""
299
- if not isinstance(other, LunarDate):
300
- return NotImplemented
301
-
302
- if self.year != other.year:
303
- return self.year < other.year
304
- if self.month != other.month:
305
- return self.month < other.month
306
- if self.is_leap != other.is_leap:
307
- return not self.is_leap # 正常月份小于闰月
308
- return self.day < other.day
309
-
310
- def __le__(self, other) -> bool:
311
- """小于等于比较"""
312
- return self == other or self < other
313
-
314
- def __gt__(self, other) -> bool:
315
- """大于比较"""
316
- return not self <= other
317
-
318
- def __ge__(self, other) -> bool:
319
- """大于等于比较"""
320
- return not self < other
147
+ def format_chinese(self):
148
+ """格式化为中文"""
149
+ leap_str = "闰" if self.is_leap else ""
150
+ return f"农历{self.year}年{leap_str}{self.month}月{self.day}日"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: staran
3
- Version: 1.0.10
3
+ Version: 1.0.11
4
4
  Summary: staran - 企业级Python日期处理库
5
5
  Home-page: https://github.com/starlxa/staran
6
6
  Author: StarAn
@@ -1,9 +1,9 @@
1
- staran/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- staran/date/__init__.py,sha256=CPVRv_g76wGRuKIoorXsqc58buoUQl5XkIqnZdugJUg,2858
1
+ staran/__init__.py,sha256=2fdUCSoO3lRBtz1lIayT3wjEZY2EnsEC-4kdqFYemLQ,1538
2
+ staran/date/__init__.py,sha256=jvim48EMYAu8vR3HZRoqALh8ADkbyQinV7oAxyF28pU,2858
3
3
  staran/date/core/__init__.py,sha256=cZmvd7X36qmXUGPrf-K0xOchzPiSONv1rw1WMi1uNXA,430
4
4
  staran/date/core/core.py,sha256=1rlVqJaZZh8PxlBcE8R6aJoHP27Xwvpc6DZ5Mv30RhU,88769
5
5
  staran/date/core/i18n.py,sha256=bvnqhVGMYvW8Lt3W4uksJw9aRZ2l4cNAy0GiYEQy4II,14677
6
- staran/date/core/lunar.py,sha256=JCs9EJOsfCXE4jgTkfZZw85-IKvjPbtx70CapEAy4sQ,11980
6
+ staran/date/core/lunar.py,sha256=CiGQIOdfh8mLJAKJ4VDzqp7IWObPr_6S1SCgULkfMuQ,5875
7
7
  staran/date/examples/__init__.py,sha256=5q6uxzeIhPcFo64gXybEozx4E4lt8TEEibFC-dF_EV0,163
8
8
  staran/date/examples/basic_usage.py,sha256=hsQZaMRR6tY9krLjmYrH7GrMkk2cGapY-bfjwsL_6YQ,4738
9
9
  staran/date/examples/enhanced_features.py,sha256=KDxw1d-h3N19oidCyeHKCSMUrOtr0sP7K5YI1fsowrw,6598
@@ -26,9 +26,9 @@ staran/date/tests/test_v108_features.py,sha256=wih6mY-fgq1aEYdvXkFqzoeSk73-8Mf9W
26
26
  staran/date/tests/test_v109_features.py,sha256=hN5m3DTQM8j_U9ilh3fN3cQvBZH4DPI7stGlsgdIEEw,10932
27
27
  staran/date/utils/__init__.py,sha256=W5DkeslSOINF7kq6wFz3l16fUmGI0XALNuJAALQeLLM,142
28
28
  staran/date/utils/helpers.py,sha256=9TlebdCr-YD4vrXjTFMXDG413gbSFwdUNyivAarIp5M,5553
29
- staran-1.0.10.dist-info/licenses/LICENSE,sha256=2EmsBIyDCono4iVXNpv5_px9qt2b7hfPq1WuyGVMNP4,1361
30
- staran-1.0.10.dist-info/METADATA,sha256=9FVvrpHWubF7sAn2YOSib0wyaghDys9_ao9A1z5s1Us,8012
31
- staran-1.0.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
32
- staran-1.0.10.dist-info/entry_points.txt,sha256=igvLxDd-ONmb_m9IwbFKMv_uMhAyb_nPfNIq3J3rZUg,54
33
- staran-1.0.10.dist-info/top_level.txt,sha256=NOUZtXSh5oSIEjHrC0lQ9WmoKtD010Q00dghWyag-Zs,7
34
- staran-1.0.10.dist-info/RECORD,,
29
+ staran-1.0.11.dist-info/licenses/LICENSE,sha256=2EmsBIyDCono4iVXNpv5_px9qt2b7hfPq1WuyGVMNP4,1361
30
+ staran-1.0.11.dist-info/METADATA,sha256=mhsT-yZaaQ6NnC_UDQQICgYv7Rx_oWZzLc6dpz1x-Ms,8012
31
+ staran-1.0.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
32
+ staran-1.0.11.dist-info/entry_points.txt,sha256=igvLxDd-ONmb_m9IwbFKMv_uMhAyb_nPfNIq3J3rZUg,54
33
+ staran-1.0.11.dist-info/top_level.txt,sha256=NOUZtXSh5oSIEjHrC0lQ9WmoKtD010Q00dghWyag-Zs,7
34
+ staran-1.0.11.dist-info/RECORD,,