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 +10 -0
- staran/tools/__init__.py +6 -6
- staran/tools/date.py +327 -222
- staran/tools/tests/__init__.py +119 -0
- staran/tools/tests/run_tests.py +241 -0
- staran/tools/tests/test_api_compatibility.py +319 -0
- staran/tools/tests/test_date.py +565 -0
- staran/tools/tests/test_logging.py +402 -0
- staran-1.0.1.dist-info/METADATA +37 -0
- staran-1.0.1.dist-info/RECORD +13 -0
- staran/banks/__init__.py +0 -30
- staran/banks/xinjiang_icbc/__init__.py +0 -90
- staran/engines/__init__.py +0 -65
- staran/engines/base.py +0 -255
- staran/engines/hive.py +0 -163
- staran/engines/spark.py +0 -252
- staran/engines/turing.py +0 -439
- staran/features/__init__.py +0 -59
- staran/features/engines.py +0 -284
- staran/features/generator.py +0 -603
- staran/features/manager.py +0 -155
- staran/features/schema.py +0 -193
- staran/models/__init__.py +0 -72
- staran/models/config.py +0 -271
- staran/models/daifa_models.py +0 -361
- staran/models/registry.py +0 -281
- staran/models/target.py +0 -321
- staran/schemas/__init__.py +0 -27
- staran/schemas/aum/__init__.py +0 -210
- staran/tools/document_generator.py +0 -350
- staran-0.6.1.dist-info/METADATA +0 -586
- staran-0.6.1.dist-info/RECORD +0 -28
- {staran-0.6.1.dist-info → staran-1.0.1.dist-info}/WHEEL +0 -0
- {staran-0.6.1.dist-info → staran-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {staran-0.6.1.dist-info → staran-1.0.1.dist-info}/top_level.txt +0 -0
staran/__init__.py
CHANGED
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.
|
42
|
-
__author__ = '
|
43
|
-
__description__ = '
|
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
|
-
|
6
|
-
|
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
|
-
"""
|
16
|
+
"""
|
17
|
+
企业级日期处理类,支持:
|
18
|
+
- 多种输入格式自动识别
|
19
|
+
- 智能格式记忆
|
20
|
+
- 统一的API命名规范
|
21
|
+
- 企业级日志记录
|
22
|
+
- 向后兼容性
|
23
|
+
"""
|
15
24
|
|
16
25
|
def __init__(self, *args, **kwargs):
|
17
|
-
"""
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
35
|
-
|
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.
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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.
|
52
|
+
self._validate_date()
|
103
53
|
else:
|
104
|
-
|
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
|
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
|
-
|
116
|
-
|
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
|
-
|
120
|
-
if
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
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
|
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
|
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
|
-
|
180
|
-
|
181
|
-
return self
|
163
|
+
# 格式化方法
|
164
|
+
def format_default(self) -> str:
|
165
|
+
return str(self)
|
182
166
|
|
183
|
-
def
|
184
|
-
|
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
|
188
|
-
|
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
|
192
|
-
|
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
|
196
|
-
|
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
|
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
|
204
|
-
|
205
|
-
|
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
|
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
|
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
|
216
|
-
"""获取输入格式类型"""
|
204
|
+
def get_format_type(self) -> str:
|
217
205
|
return self._input_format_type
|
218
206
|
|
219
|
-
def
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
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
|
-
|
234
|
-
|
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
|
-
|
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
|
256
|
-
|
257
|
-
|
258
|
-
|
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
|
-
|
261
|
-
|
262
|
-
|
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
|
-
|
265
|
-
|
266
|
-
return self.
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
299
|
-
|
300
|
-
return
|
403
|
+
@classmethod
|
404
|
+
def get_version(cls) -> str:
|
405
|
+
return "1.0.1"
|