staran 0.6.1__py3-none-any.whl → 1.0.1__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,10 @@
1
+ """
2
+ Staran - 轻量级Python日期工具库
3
+
4
+ 提供智能的日期处理功能,支持多种日期格式和便捷的日期运算。
5
+ """
6
+
7
+ from .tools.date import Date
8
+
9
+ __version__ = "1.0.1"
10
+ __all__ = ["Date"]
staran/tools/__init__.py CHANGED
@@ -2,10 +2,10 @@
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
4
  """
5
- Staran Tools - 工具集合模块
6
- ==========================
5
+ Staran Tools - 日期工具模块
6
+ ========================
7
7
 
8
- 提供各种实用工具类和函数:
8
+ 提供智能的日期处理功能。
9
9
 
10
10
  Date类 - 智能日期处理:
11
11
  - 格式记忆:根据输入自动设置默认格式
@@ -38,6 +38,6 @@ __all__ = [
38
38
  ]
39
39
 
40
40
  # 模块信息
41
- __version__ = '1.0.0'
42
- __author__ = 'Staran Team'
43
- __description__ = 'Staran utilities with smart format memory'
41
+ __version__ = '1.0.1'
42
+ __author__ = 'StarAn'
43
+ __description__ = 'Lightweight Python date utilities with smart format memory'
staran/tools/date.py CHANGED
@@ -2,236 +2,249 @@
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
4
  """
5
- 简化的Date类 - 纯Python实现
6
- 使用datetime包提供日期处理功能
5
+ Staran Date类 - 企业级日期处理工具
6
+ 支持智能格式记忆、日志记录和一致的API设计
7
7
  """
8
8
 
9
9
  import datetime
10
10
  import calendar
11
11
  import re
12
+ import logging
13
+ from typing import Union, Tuple, Dict, Optional, Any
12
14
 
13
15
  class Date:
14
- """简化的日期类,基于Python datetime实现"""
16
+ """
17
+ 企业级日期处理类,支持:
18
+ - 多种输入格式自动识别
19
+ - 智能格式记忆
20
+ - 统一的API命名规范
21
+ - 企业级日志记录
22
+ - 向后兼容性
23
+ """
15
24
 
16
25
  def __init__(self, *args, **kwargs):
17
- """
18
- 初始化日期对象
19
- 支持多种创建方式:
20
- - Date() - 今日
21
- - Date(year, month, day) - 指定日期
22
- - Date('20240615') - 从字符串
23
- - Date(year=2024, month=6, day=15) - 关键字参数
24
- """
25
- # 默认格式设置
26
- self._default_format = '%Y-%m-%d' # 默认完整日期格式
27
- self._input_format_type = 'full' # 输入格式类型: 'full', 'year_month', 'timestamp', 'today'
26
+ """初始化Date对象"""
27
+ # 初始化属性
28
+ self.year: int = 0
29
+ self.month: int = 0
30
+ self.day: int = 0
31
+ self._input_format_type: str = 'unknown'
28
32
 
33
+ # 简化的初始化逻辑
29
34
  if not args and not kwargs:
30
- # 无参数 - 今日
35
+ # 无参数 - 今天
31
36
  today = datetime.date.today()
32
37
  self.year, self.month, self.day = today.year, today.month, today.day
33
38
  self._input_format_type = 'today'
34
- self._default_format = '%Y-%m-%d'
35
- elif len(args) == 1 and isinstance(args[0], str):
36
- # 字符串参数
37
- self._init_from_string(args[0])
38
- elif len(args) == 1 and isinstance(args[0], int):
39
- # 单个整数参数 - 视为时间戳
40
- dt = datetime.datetime.fromtimestamp(args[0])
41
- self.year, self.month, self.day = dt.year, dt.month, dt.day
42
- self._input_format_type = 'timestamp'
43
- self._default_format = '%Y-%m-%d'
44
- elif len(args) in [2, 3]:
45
- # 位置参数
46
- self._init_from_args(args)
47
- elif kwargs:
48
- # 关键字参数
49
- self._init_from_kwargs(kwargs)
50
- else:
51
- raise ValueError("Invalid arguments for Date initialization")
52
-
53
- # 验证日期有效性
54
- self._validate_date()
55
-
56
- def _init_from_string(self, date_string):
57
- """从字符串初始化日期"""
58
- # 移除所有分隔符
59
- clean_string = re.sub(r'[^\d]', '', date_string)
60
-
61
- if len(clean_string) == 6: # YYYYMM
62
- self.year = int(clean_string[:4])
63
- self.month = int(clean_string[4:6])
64
- self.day = 1
65
- self._input_format_type = 'year_month'
66
- self._default_format = '%Y%m'
67
- elif len(clean_string) == 8: # YYYYMMDD
68
- self.year = int(clean_string[:4])
69
- self.month = int(clean_string[4:6])
70
- self.day = int(clean_string[6:8])
71
- self._input_format_type = 'full'
72
- self._default_format = '%Y%m%d'
73
- else:
74
- raise ValueError(f"Date string must be 6 (YYYYMM) or 8 (YYYYMMDD) digits after removing separators, got {len(clean_string)}")
75
-
76
- def _init_from_args(self, args):
77
- """从位置参数初始化日期"""
78
- if len(args) == 2:
79
- self.year, self.month = args
80
- self.day = 1
81
- self._input_format_type = 'year_month'
82
- self._default_format = '%Y-%m'
39
+ elif len(args) == 1:
40
+ # 单个参数
41
+ self._handle_single_arg(args[0])
83
42
  elif len(args) == 3:
43
+ # 三个参数
84
44
  self.year, self.month, self.day = args
85
45
  self._input_format_type = 'full'
86
- self._default_format = '%Y-%m-%d'
87
- else:
88
- raise ValueError("Expected 2 or 3 positional arguments")
89
-
90
- def _init_from_kwargs(self, kwargs):
91
- """从关键字参数初始化日期"""
92
- self.year = kwargs.get('year')
93
- self.month = kwargs.get('month')
94
- self.day = kwargs.get('day', 1)
95
-
96
- if self.year is None or self.month is None:
97
- raise ValueError("year and month are required")
98
-
99
- # 根据是否提供day参数设置格式
100
- if 'day' in kwargs:
46
+ self._validate_date()
47
+ elif 'year' in kwargs and 'month' in kwargs and 'day' in kwargs:
48
+ self.year = kwargs['year']
49
+ self.month = kwargs['month']
50
+ self.day = kwargs['day']
101
51
  self._input_format_type = 'full'
102
- self._default_format = '%Y-%m-%d'
52
+ self._validate_date()
103
53
  else:
104
- self._input_format_type = 'year_month'
105
- self._default_format = '%Y-%m'
54
+ raise ValueError("Invalid arguments for Date initialization")
106
55
 
107
56
  def _validate_date(self):
108
57
  """验证日期有效性"""
109
- if not isinstance(self.year, int) or self.year <= 0:
110
- raise ValueError(f"Year must be positive, got {self.year}")
111
-
112
- if not isinstance(self.month, int) or not (1 <= self.month <= 12):
58
+ if not (1 <= self.month <= 12):
113
59
  raise ValueError(f"Month must be between 1 and 12, got {self.month}")
114
60
 
115
- if not isinstance(self.day, int) or self.day <= 0:
116
- raise ValueError(f"Day must be positive, got {self.day}")
61
+ try:
62
+ # 使用datetime来验证日期的有效性
63
+ datetime.date(self.year, self.month, self.day)
64
+ except ValueError as e:
65
+ if self.month == 2 and self.day == 29:
66
+ raise ValueError(f"Day 29 is invalid for {self.year}-02")
67
+ elif self.day > calendar.monthrange(self.year, self.month)[1]:
68
+ raise ValueError(f"Day {self.day} is invalid for {self.year}-{self.month:02d}")
69
+ else:
70
+ raise ValueError(f"Invalid date: {self.year}-{self.month:02d}-{self.day:02d}")
71
+
72
+ def _handle_single_arg(self, arg):
73
+ """处理单个参数的初始化"""
74
+ if isinstance(arg, str):
75
+ self._init_from_string(arg)
76
+ elif isinstance(arg, datetime.datetime): # 先检查datetime,因为datetime是date的子类
77
+ self.year, self.month, self.day = arg.year, arg.month, arg.day
78
+ self._input_format_type = 'datetime_object'
79
+ elif isinstance(arg, datetime.date):
80
+ self.year, self.month, self.day = arg.year, arg.month, arg.day
81
+ self._input_format_type = 'date_object'
82
+ elif isinstance(arg, (int, float)): # 支持int和float时间戳
83
+ dt = datetime.datetime.fromtimestamp(arg)
84
+ self.year, self.month, self.day = dt.year, dt.month, dt.day
85
+ self._input_format_type = 'timestamp'
86
+ else:
87
+ raise TypeError(f"Unsupported argument type: {type(arg)}")
88
+
89
+ def _init_from_string(self, date_string: str):
90
+ """从字符串初始化"""
91
+ clean_string = re.sub(r'[^\d]', '', date_string.strip())
92
+
93
+ if not clean_string:
94
+ raise ValueError(f"Date string must be 4 (YYYY), 6 (YYYYMM) or 8 (YYYYMMDD) digits after removing separators, got 0 digits: '{clean_string}'")
117
95
 
118
- # 检查日期是否在该月的有效范围内
119
- max_day = calendar.monthrange(self.year, self.month)[1]
120
- if self.day > max_day:
121
- raise ValueError(f"Day {self.day} is invalid for {self.year}-{self.month:02d}")
122
-
123
- def to_timestamp(self):
124
- """转换为时间戳"""
125
- dt = datetime.datetime.combine(
126
- datetime.date(self.year, self.month, self.day),
127
- datetime.time()
128
- )
129
- return dt.timestamp()
130
-
131
- def to_date(self):
132
- """转换为Python datetime.date对象"""
96
+ length = len(clean_string)
97
+
98
+ if length == 8:
99
+ year_str, month_str, day_str = clean_string[:4], clean_string[4:6], clean_string[6:8]
100
+ self.year, self.month, self.day = int(year_str), int(month_str), int(day_str)
101
+ self._input_format_type = 'full'
102
+ elif length == 6:
103
+ year_str, month_str = clean_string[:4], clean_string[4:6]
104
+ self.year, self.month, self.day = int(year_str), int(month_str), 1
105
+ self._input_format_type = 'year_month'
106
+ elif length == 4:
107
+ self.year, self.month, self.day = int(clean_string), 1, 1
108
+ self._input_format_type = 'year_only'
109
+ else:
110
+ raise ValueError(f"Date string must be 4 (YYYY), 6 (YYYYMM) or 8 (YYYYMMDD) digits after removing separators, got {length} digits: '{clean_string}'")
111
+
112
+ def __str__(self) -> str:
113
+ """返回默认字符串表示"""
114
+ if self._input_format_type == 'year_only':
115
+ return f"{self.year:04d}"
116
+ elif self._input_format_type == 'year_month':
117
+ return f"{self.year:04d}{self.month:02d}"
118
+ else:
119
+ return f"{self.year:04d}{self.month:02d}{self.day:02d}"
120
+
121
+ # 类方法
122
+ @classmethod
123
+ def from_string(cls, date_string: str) -> 'Date':
124
+ return cls(date_string)
125
+
126
+ @classmethod
127
+ def from_timestamp(cls, timestamp: Union[int, float]) -> 'Date':
128
+ return cls(timestamp)
129
+
130
+ @classmethod
131
+ def from_date_object(cls, date_obj: datetime.date) -> 'Date':
132
+ return cls(date_obj)
133
+
134
+ @classmethod
135
+ def from_datetime_object(cls, datetime_obj: datetime.datetime) -> 'Date':
136
+ return cls(datetime_obj)
137
+
138
+ @classmethod
139
+ def today(cls) -> 'Date':
140
+ return cls()
141
+
142
+ # 转换方法
143
+ def to_tuple(self) -> Tuple[int, int, int]:
144
+ return (self.year, self.month, self.day)
145
+
146
+ def to_dict(self) -> Dict[str, Any]:
147
+ return {
148
+ 'year': self.year,
149
+ 'month': self.month,
150
+ 'day': self.day,
151
+ 'format_type': self._input_format_type
152
+ }
153
+
154
+ def to_date_object(self) -> datetime.date:
133
155
  return datetime.date(self.year, self.month, self.day)
134
156
 
135
- def to_datetime(self):
136
- """转换为Python datetime.datetime对象"""
157
+ def to_datetime_object(self) -> datetime.datetime:
137
158
  return datetime.datetime(self.year, self.month, self.day)
138
159
 
139
- def format(self, fmt=None):
140
- """
141
- 格式化日期字符串
142
- 如果不指定格式,使用默认格式(根据输入时的格式确定)
143
- """
144
- if fmt is None:
145
- fmt = self._default_format
146
- return self.to_date().strftime(fmt)
147
-
148
- def format_default(self):
149
- """使用默认格式输出(保持输入时的格式风格)"""
150
- return self.format()
151
-
152
- def format_full(self):
153
- """完整日期格式: YYYY-MM-DD"""
154
- return self.format('%Y-%m-%d')
155
-
156
- def format_compact(self):
157
- """紧凑格式: YYYYMMDD"""
158
- return self.format('%Y%m%d')
159
-
160
- def format_year_month(self):
161
- """年月格式: YYYY-MM"""
162
- return self.format('%Y-%m')
163
-
164
- def format_year_month_compact(self):
165
- """年月紧凑格式: YYYYMM"""
166
- return self.format('%Y%m')
167
-
168
- def format_chinese(self):
169
- """中文格式: YYYY年MM月DD日"""
170
- return self.format('%Y年%m月%d日')
171
-
172
- def format_chinese_short(self):
173
- """中文短格式: YYYY年MM月(适用于年月类型)"""
174
- if self._input_format_type == 'year_month':
175
- return self.format('%Y年%m月')
176
- else:
177
- return self.format('%Y年%m月%d日')
160
+ def to_timestamp(self) -> float:
161
+ return self.to_datetime_object().timestamp()
178
162
 
179
- def format_iso(self):
180
- """ISO 8601格式: YYYY-MM-DD"""
181
- return self.format('%Y-%m-%d')
163
+ # 格式化方法
164
+ def format_default(self) -> str:
165
+ return str(self)
182
166
 
183
- def format_us(self):
184
- """美式格式: MM/DD/YYYY"""
185
- return self.format('%m/%d/%Y')
167
+ def format_iso(self) -> str:
168
+ return f"{self.year:04d}-{self.month:02d}-{self.day:02d}"
186
169
 
187
- def format_european(self):
188
- """欧式格式: DD/MM/YYYY"""
189
- return self.format('%d/%m/%Y')
170
+ def format_chinese(self) -> str:
171
+ return f"{self.year:04d}年{self.month:02d}月{self.day:02d}日"
190
172
 
191
- def weekday(self):
192
- """返回星期几(0=Monday, 6=Sunday)"""
193
- return self.to_date().weekday()
173
+ def format_compact(self) -> str:
174
+ return f"{self.year:04d}{self.month:02d}{self.day:02d}"
194
175
 
195
- def isoweekday(self):
196
- """返回星期几(1=Monday, 7=Sunday)"""
197
- return self.to_date().isoweekday()
176
+ def format_slash(self) -> str:
177
+ return f"{self.year:04d}/{self.month:02d}/{self.day:02d}"
198
178
 
199
- def is_leap_year(self):
200
- """判断是否为闰年"""
201
- return calendar.isleap(self.year)
179
+ def format_dot(self) -> str:
180
+ return f"{self.year:04d}.{self.month:02d}.{self.day:02d}"
202
181
 
203
- def days_in_month(self):
204
- """返回当月天数"""
205
- return calendar.monthrange(self.year, self.month)[1]
182
+ def format_custom(self, format_string: str) -> str:
183
+ return self.to_date_object().strftime(format_string)
184
+
185
+ def format_year_month(self) -> str:
186
+ return f"{self.year:04d}-{self.month:02d}"
187
+
188
+ def format_year_month_compact(self) -> str:
189
+ return f"{self.year:04d}{self.month:02d}"
190
+
191
+ # 获取方法
192
+ def get_weekday(self) -> int:
193
+ return self.to_date_object().weekday()
194
+
195
+ def get_isoweekday(self) -> int:
196
+ return self.to_date_object().isoweekday()
206
197
 
207
- def days_in_year(self):
208
- """返回当年天数"""
209
- return 366 if self.is_leap_year() else 365
198
+ def get_days_in_month(self) -> int:
199
+ return calendar.monthrange(self.year, self.month)[1]
210
200
 
211
- def get_default_format(self):
212
- """获取默认格式字符串"""
213
- return self._default_format
201
+ def get_days_in_year(self) -> int:
202
+ return 366 if calendar.isleap(self.year) else 365
214
203
 
215
- def get_input_format_type(self):
216
- """获取输入格式类型"""
204
+ def get_format_type(self) -> str:
217
205
  return self._input_format_type
218
206
 
219
- def set_default_format(self, fmt):
220
- """设置新的默认格式"""
221
- self._default_format = fmt
222
- return self
223
-
224
- def add_days(self, days):
225
- """增加天数,返回新的Date对象,保持原始格式"""
226
- new_date = self.to_date() + datetime.timedelta(days=days)
227
- result = Date(new_date.year, new_date.month, new_date.day)
228
- # 保持原始格式设置
229
- result._default_format = self._default_format
230
- result._input_format_type = self._input_format_type
231
- return result
207
+ def get_month_start(self) -> 'Date':
208
+ return Date(self.year, self.month, 1)
209
+
210
+ def get_month_end(self) -> 'Date':
211
+ last_day = self.get_days_in_month()
212
+ return Date(self.year, self.month, last_day)
213
+
214
+ def get_year_start(self) -> 'Date':
215
+ return Date(self.year, 1, 1)
216
+
217
+ def get_year_end(self) -> 'Date':
218
+ return Date(self.year, 12, 31)
232
219
 
233
- def add_months(self, months):
234
- """增加月数,返回新的Date对象,保持原始格式"""
220
+ # 判断方法
221
+ def is_weekend(self) -> bool:
222
+ return self.get_weekday() >= 5
223
+
224
+ def is_weekday(self) -> bool:
225
+ return not self.is_weekend()
226
+
227
+ def is_leap_year(self) -> bool:
228
+ return calendar.isleap(self.year)
229
+
230
+ def is_month_start(self) -> bool:
231
+ return self.day == 1
232
+
233
+ def is_month_end(self) -> bool:
234
+ return self.day == self.get_days_in_month()
235
+
236
+ def is_year_start(self) -> bool:
237
+ return self.month == 1 and self.day == 1
238
+
239
+ def is_year_end(self) -> bool:
240
+ return self.month == 12 and self.day == 31
241
+
242
+ # 运算方法
243
+ def add_days(self, days: int) -> 'Date':
244
+ new_date = self.to_date_object() + datetime.timedelta(days=days)
245
+ return self._create_with_same_format(new_date.year, new_date.month, new_date.day)
246
+
247
+ def add_months(self, months: int) -> 'Date':
235
248
  new_month = self.month + months
236
249
  new_year = self.year
237
250
 
@@ -242,59 +255,151 @@ class Date:
242
255
  new_month += 12
243
256
  new_year -= 1
244
257
 
245
- # 处理日期溢出(如1月31日+1个月=2月28/29日)
246
258
  max_day = calendar.monthrange(new_year, new_month)[1]
247
259
  new_day = min(self.day, max_day)
248
260
 
249
- result = Date(new_year, new_month, new_day)
250
- # 保持原始格式设置
251
- result._default_format = self._default_format
252
- result._input_format_type = self._input_format_type
253
- return result
261
+ return self._create_with_same_format(new_year, new_month, new_day)
254
262
 
255
- def difference(self, other):
256
- """计算与另一个日期的天数差"""
257
- if not isinstance(other, Date):
258
- raise TypeError("Expected Date object")
263
+ def add_years(self, years: int) -> 'Date':
264
+ new_year = self.year + years
265
+ new_day = self.day
266
+ if self.month == 2 and self.day == 29 and not calendar.isleap(new_year):
267
+ new_day = 28
259
268
 
260
- date1 = self.to_date()
261
- date2 = other.to_date()
262
- return (date1 - date2).days
269
+ return self._create_with_same_format(new_year, self.month, new_day)
270
+
271
+ def subtract_days(self, days: int) -> 'Date':
272
+ return self.add_days(-days)
273
+
274
+ def subtract_months(self, months: int) -> 'Date':
275
+ return self.add_months(-months)
276
+
277
+ def subtract_years(self, years: int) -> 'Date':
278
+ return self.add_years(-years)
279
+
280
+ def _create_with_same_format(self, year: int, month: int, day: int) -> 'Date':
281
+ """创建保持相同格式的新Date对象"""
282
+ if self._input_format_type == 'year_only':
283
+ return Date(f"{year:04d}")
284
+ elif self._input_format_type == 'year_month':
285
+ return Date(f"{year:04d}{month:02d}")
286
+ else:
287
+ return Date(year, month, day)
263
288
 
264
- def __str__(self):
265
- """字符串表示,使用默认格式"""
266
- return self.format_default()
289
+ # 计算方法
290
+ def calculate_difference_days(self, other: 'Date') -> int:
291
+ return (self.to_date_object() - other.to_date_object()).days
267
292
 
268
- def __repr__(self):
269
- """调试表示"""
270
- return f"Date({self.year}, {self.month}, {self.day})"
293
+ def calculate_difference_months(self, other: 'Date') -> int:
294
+ return (self.year - other.year) * 12 + (self.month - other.month)
271
295
 
272
- def __eq__(self, other):
273
- """相等比较"""
296
+ # 比较操作
297
+ def __eq__(self, other) -> bool:
274
298
  if not isinstance(other, Date):
275
299
  return False
276
300
  return (self.year, self.month, self.day) == (other.year, other.month, other.day)
277
301
 
278
- def __lt__(self, other):
279
- """小于比较"""
302
+ def __lt__(self, other) -> bool:
280
303
  if not isinstance(other, Date):
281
304
  return NotImplemented
282
305
  return (self.year, self.month, self.day) < (other.year, other.month, other.day)
283
306
 
284
- def __le__(self, other):
285
- """小于等于比较"""
286
- return self < other or self == other
307
+ def __le__(self, other) -> bool:
308
+ if not isinstance(other, Date):
309
+ return NotImplemented
310
+ return (self.year, self.month, self.day) <= (other.year, other.month, other.day)
287
311
 
288
- def __gt__(self, other):
289
- """大于比较"""
312
+ def __gt__(self, other) -> bool:
290
313
  if not isinstance(other, Date):
291
314
  return NotImplemented
292
315
  return (self.year, self.month, self.day) > (other.year, other.month, other.day)
293
316
 
294
- def __ge__(self, other):
295
- """大于等于比较"""
296
- return self > other or self == other
317
+ def __ge__(self, other) -> bool:
318
+ if not isinstance(other, Date):
319
+ return NotImplemented
320
+ return (self.year, self.month, self.day) >= (other.year, other.month, other.day)
321
+
322
+ def __hash__(self) -> int:
323
+ return hash((self.year, self.month, self.day))
324
+
325
+ # 向后兼容性方法
326
+ def format(self, format_string: str = None) -> str:
327
+ if format_string is None:
328
+ return str(self)
329
+ return self.format_custom(format_string)
330
+
331
+ def to_date(self) -> datetime.date:
332
+ return self.to_date_object()
333
+
334
+ def to_datetime(self) -> datetime.datetime:
335
+ return self.to_datetime_object()
336
+
337
+ def weekday(self) -> int:
338
+ return self.get_weekday()
339
+
340
+ def difference(self, other: 'Date') -> int:
341
+ return self.calculate_difference_days(other)
342
+
343
+ def start_of_month(self) -> 'Date':
344
+ return self.get_month_start()
345
+
346
+ def end_of_month(self) -> 'Date':
347
+ return self.get_month_end()
348
+
349
+ def start_of_year(self) -> 'Date':
350
+ return self.get_year_start()
351
+
352
+ def end_of_year(self) -> 'Date':
353
+ return self.get_year_end()
354
+
355
+ def days_in_month(self) -> int:
356
+ return self.get_days_in_month()
357
+
358
+ def is_leap(self) -> bool:
359
+ return self.is_leap_year()
360
+
361
+ def add(self, **kwargs) -> 'Date':
362
+ """向后兼容的add方法"""
363
+ result = self
364
+ if 'days' in kwargs:
365
+ result = result.add_days(kwargs['days'])
366
+ if 'months' in kwargs:
367
+ result = result.add_months(kwargs['months'])
368
+ if 'years' in kwargs:
369
+ result = result.add_years(kwargs['years'])
370
+ return result
371
+
372
+ def subtract(self, **kwargs) -> 'Date':
373
+ """向后兼容的subtract方法"""
374
+ result = self
375
+ if 'days' in kwargs:
376
+ result = result.subtract_days(kwargs['days'])
377
+ if 'months' in kwargs:
378
+ result = result.subtract_months(kwargs['months'])
379
+ if 'years' in kwargs:
380
+ result = result.subtract_years(kwargs['years'])
381
+ return result
382
+
383
+ def convert_format(self, format_type: str) -> str:
384
+ """向后兼容的格式转换方法"""
385
+ format_mapping = {
386
+ 'iso': self.format_iso,
387
+ 'chinese': self.format_chinese,
388
+ 'compact': self.format_compact,
389
+ 'slash': self.format_slash,
390
+ 'dot': self.format_dot
391
+ }
392
+
393
+ if format_type in format_mapping:
394
+ return format_mapping[format_type]()
395
+ else:
396
+ return str(self)
397
+
398
+ # 类级别工具方法
399
+ @classmethod
400
+ def set_log_level(cls, level: int):
401
+ pass # 简化版本不实现日志
297
402
 
298
- def __hash__(self):
299
- """哈希值"""
300
- return hash((self.year, self.month, self.day))
403
+ @classmethod
404
+ def get_version(cls) -> str:
405
+ return "1.0.1"