upplib 3.3.1__py3-none-any.whl → 3.3.9__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.
- upplib/__init__.py +6 -2
- upplib/config_data.py +1 -1
- upplib/datetime_function.py +256 -0
- upplib/{file.py → file_function.py} +48 -0
- upplib/{file_text.py → file_to_text.py} +5 -435
- upplib/index.py +0 -252
- upplib/query_log.py +1 -0
- upplib/text_to_file.py +389 -0
- {upplib-3.3.1.dist-info → upplib-3.3.9.dist-info}/METADATA +1 -1
- {upplib-3.3.1.dist-info → upplib-3.3.9.dist-info}/RECORD +13 -11
- {upplib-3.3.1.dist-info → upplib-3.3.9.dist-info}/WHEEL +0 -0
- {upplib-3.3.1.dist-info → upplib-3.3.9.dist-info}/licenses/LICENSE +0 -0
- {upplib-3.3.1.dist-info → upplib-3.3.9.dist-info}/top_level.txt +0 -0
upplib/__init__.py
CHANGED
|
@@ -3,12 +3,16 @@ from upplib.common_package import *
|
|
|
3
3
|
|
|
4
4
|
# 引入自定义的全部的包
|
|
5
5
|
from upplib.index import *
|
|
6
|
+
from upplib.datetime_function import *
|
|
6
7
|
# 引入通用的工具包
|
|
7
8
|
from upplib.util import *
|
|
8
9
|
|
|
9
10
|
# 有关文件操作类的包
|
|
10
|
-
from upplib.
|
|
11
|
-
from upplib.
|
|
11
|
+
from upplib.file_function import *
|
|
12
|
+
from upplib.file_to_text import *
|
|
13
|
+
from upplib.text_to_file import *
|
|
14
|
+
|
|
15
|
+
from upplib.clean_up_msg import *
|
|
12
16
|
|
|
13
17
|
from upplib.config_data import *
|
|
14
18
|
|
upplib/config_data.py
CHANGED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
from upplib import *
|
|
2
|
+
from datetime import datetime, timezone, timedelta
|
|
3
|
+
from typing import Any, Optional, Union
|
|
4
|
+
from upplib.common_package import *
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_tz(tz_info: Union[str, timezone]) -> timezone:
|
|
8
|
+
"""将时区信息转换为timezone对象"""
|
|
9
|
+
if isinstance(tz_info, timezone):
|
|
10
|
+
return tz_info
|
|
11
|
+
if not isinstance(tz_info, str):
|
|
12
|
+
raise ValueError(f"无效的时区格式: {tz_info}")
|
|
13
|
+
tz_str = tz_info.upper()
|
|
14
|
+
if tz_str == "UTC":
|
|
15
|
+
return timezone.utc
|
|
16
|
+
# 处理纯偏移格式,如+07:00、-05:30
|
|
17
|
+
offset_match = re.match(r"^([+-])(\d{1,2}):(\d{2})$", tz_str)
|
|
18
|
+
if offset_match:
|
|
19
|
+
sign = offset_match.group(1)
|
|
20
|
+
hours = int(offset_match.group(2))
|
|
21
|
+
minutes = int(offset_match.group(3))
|
|
22
|
+
# 计算总偏移小时数
|
|
23
|
+
total_hours = hours + minutes / 60
|
|
24
|
+
if sign == "-":
|
|
25
|
+
total_hours = -total_hours
|
|
26
|
+
return timezone(timedelta(hours=total_hours))
|
|
27
|
+
# 处理GMT格式,如GMT+08:00或GMT-5
|
|
28
|
+
gmt_match = re.match(r"GMT([+-]\d{1,2})(:\d{2})?$", tz_str)
|
|
29
|
+
if gmt_match:
|
|
30
|
+
hours = int(gmt_match.group(1))
|
|
31
|
+
return timezone(timedelta(hours=hours))
|
|
32
|
+
# 处理UTC格式,如UTC+8或UTC-05:00
|
|
33
|
+
utc_match = re.match(r"UTC([+-]\d{1,2})(:\d{2})?$", tz_str)
|
|
34
|
+
if utc_match:
|
|
35
|
+
hours = int(utc_match.group(1))
|
|
36
|
+
return timezone(timedelta(hours=hours))
|
|
37
|
+
raise ValueError(f"不支持的时区格式: {tz_info}")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def to_datetime(
|
|
41
|
+
s: Any = None,
|
|
42
|
+
pattern: str = None,
|
|
43
|
+
r_str: bool = False,
|
|
44
|
+
error_is_none: bool = False,
|
|
45
|
+
tz: Optional[Union[str, timezone]] = None,
|
|
46
|
+
default_tz: Union[str, timezone] = None
|
|
47
|
+
) -> Union[datetime, str, None]:
|
|
48
|
+
"""
|
|
49
|
+
将字符串或时间戳转换为 datetime 对象,支持时区处理。
|
|
50
|
+
error_is_none : 当发生错误的时候,是否返回 None
|
|
51
|
+
"""
|
|
52
|
+
# 默认时区为 +08:00
|
|
53
|
+
default_tz = default_tz or '+08:00'
|
|
54
|
+
|
|
55
|
+
use_default_time = False
|
|
56
|
+
if s is None or s == '':
|
|
57
|
+
dt = datetime.now(get_tz(default_tz))
|
|
58
|
+
else:
|
|
59
|
+
s = str(s).strip()
|
|
60
|
+
dt = None
|
|
61
|
+
|
|
62
|
+
# 1. 尝试解析时间戳
|
|
63
|
+
if re.match(r"^\d{1,19}$", s):
|
|
64
|
+
timestamp = int(s)
|
|
65
|
+
if len(s) > 10: # 毫秒级时间戳
|
|
66
|
+
timestamp = timestamp // 1000
|
|
67
|
+
# 先转为无时区的 datetime
|
|
68
|
+
dt = datetime.fromtimestamp(timestamp)
|
|
69
|
+
dt = dt.replace(tzinfo=get_tz(default_tz))
|
|
70
|
+
|
|
71
|
+
# 2. 尝试解析 ISO 8601 格式
|
|
72
|
+
if dt is None:
|
|
73
|
+
try:
|
|
74
|
+
dt = datetime.fromisoformat(s)
|
|
75
|
+
except ValueError:
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
# 3. 尝试解析带GMT时区的格式,如'2025/09/16 17:32:17.896 GMT+08:00'
|
|
79
|
+
if dt is None:
|
|
80
|
+
gmt_pattern = r"^(\d{4})[/-](\d{2})[/-](\d{2}) (\d{2}):(\d{2}):(\d{2})(\.\d+)? (GMT[+-]\d{1,2}(:\d{2})?)$"
|
|
81
|
+
match = re.match(gmt_pattern, s)
|
|
82
|
+
if match:
|
|
83
|
+
try:
|
|
84
|
+
# 提取日期时间部分
|
|
85
|
+
year, month, day = map(int, match.group(1, 2, 3))
|
|
86
|
+
hour, minute, second = map(int, match.group(4, 5, 6))
|
|
87
|
+
microsecond = 0
|
|
88
|
+
if match.group(7):
|
|
89
|
+
# 处理毫秒/微秒部分
|
|
90
|
+
microsecond = int(float(match.group(7)) * 1e6)
|
|
91
|
+
|
|
92
|
+
# 创建datetime对象
|
|
93
|
+
dt = datetime(year, month, day, hour, minute, second, microsecond)
|
|
94
|
+
|
|
95
|
+
# 应用时区
|
|
96
|
+
tz_info = get_tz(match.group(8))
|
|
97
|
+
dt = dt.replace(tzinfo=tz_info)
|
|
98
|
+
except ValueError:
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
# 4. 使用指定的pattern解析
|
|
102
|
+
if dt is None and pattern is not None:
|
|
103
|
+
try:
|
|
104
|
+
# 移除可能的毫秒部分
|
|
105
|
+
s_without_ms = s.split('.')[0]
|
|
106
|
+
dt = datetime.strptime(s_without_ms, pattern)
|
|
107
|
+
except ValueError:
|
|
108
|
+
pass
|
|
109
|
+
|
|
110
|
+
# 5. 尝试解析YYYY-MM-DD HH:MM:SS或YYYY/MM/DD HH:MM:SS格式
|
|
111
|
+
if dt is None:
|
|
112
|
+
# 尝试处理不带时区的格式
|
|
113
|
+
formats = ["%Y-%m-%d %H:%M:%S", "%Y/%m/%d %H:%M:%S"]
|
|
114
|
+
for fmt in formats:
|
|
115
|
+
try:
|
|
116
|
+
# 移除可能的毫秒和时区部分
|
|
117
|
+
s_clean = re.sub(r"(\.\d+)|[TZ]|GMT.*$", " ", s).strip()
|
|
118
|
+
dt = datetime.strptime(s_clean, fmt)
|
|
119
|
+
break
|
|
120
|
+
except ValueError:
|
|
121
|
+
continue
|
|
122
|
+
|
|
123
|
+
if dt is None:
|
|
124
|
+
use_default_time = True
|
|
125
|
+
dt = datetime.now()
|
|
126
|
+
|
|
127
|
+
# 确保无时区时附加默认时区
|
|
128
|
+
if dt.tzinfo is None:
|
|
129
|
+
dt = dt.replace(tzinfo=get_tz(default_tz))
|
|
130
|
+
|
|
131
|
+
# 转换为目标时区
|
|
132
|
+
if tz is not None:
|
|
133
|
+
dt = dt.astimezone(get_tz(tz))
|
|
134
|
+
|
|
135
|
+
if error_is_none and use_default_time:
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
return dt.isoformat() if r_str else dt
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# 将字符串 s 转化成 datetime, 然后再次转化成 str
|
|
142
|
+
def to_datetime_str(s: Any = None,
|
|
143
|
+
pattern: str = None,
|
|
144
|
+
pattern_str: str = None,
|
|
145
|
+
tz: Optional[Union[str, timezone]] = None,
|
|
146
|
+
default_tz: Union[str, timezone] = None) -> datetime | str:
|
|
147
|
+
"""
|
|
148
|
+
将 s 先转成 datetime, 然后再转成字符串
|
|
149
|
+
|
|
150
|
+
:param s: 输入值(可以是字符串或其他类型)
|
|
151
|
+
"""
|
|
152
|
+
r_s = to_datetime(s, pattern=pattern, tz=tz, r_str=False, default_tz=default_tz)
|
|
153
|
+
if pattern_str is None:
|
|
154
|
+
iso_str = r_s.isoformat()
|
|
155
|
+
if '.' not in iso_str:
|
|
156
|
+
# '2025-10-09T10:52:41+08:00'
|
|
157
|
+
return iso_str
|
|
158
|
+
parts = iso_str.split('.')
|
|
159
|
+
time_zone_part = parts[1]
|
|
160
|
+
time_zone_str = tz
|
|
161
|
+
millisecond_part = time_zone_part[:3]
|
|
162
|
+
for a in ['+', '-']:
|
|
163
|
+
if a in time_zone_part:
|
|
164
|
+
time_zone_str = a + time_zone_part.split(a)[-1]
|
|
165
|
+
return parts[0] + '.' + millisecond_part + time_zone_str
|
|
166
|
+
else:
|
|
167
|
+
return r_s.strftime(pattern_str)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def to_datetime_format(s: Any = None,
|
|
171
|
+
pattern_str: str = "%Y-%m-%d %H:%M:%S") -> datetime | str:
|
|
172
|
+
return to_datetime_str(s, pattern=None, pattern_str=pattern_str, tz=None)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def to_datetime_format__6(s: Any = None,
|
|
176
|
+
pattern_str: str = "%Y-%m-%d %H:%M:%S") -> datetime | str:
|
|
177
|
+
return to_datetime_str(s, pattern=None, pattern_str=pattern_str, tz='-06:00')
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def to_datetime_format_7(s: Any = None,
|
|
181
|
+
pattern_str: str = "%Y-%m-%d %H:%M:%S") -> datetime | str:
|
|
182
|
+
return to_datetime_str(s, pattern=None, pattern_str=pattern_str, tz='+07:00')
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def to_datetime_format_8(s: Any = None,
|
|
186
|
+
pattern_str: str = "%Y-%m-%d %H:%M:%S") -> datetime | str:
|
|
187
|
+
return to_datetime_str(s, pattern=None, pattern_str=pattern_str, tz='+08:00')
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
# 时间加减
|
|
191
|
+
def to_datetime_add(s: Any = None,
|
|
192
|
+
days: int = 0,
|
|
193
|
+
seconds: int = 0,
|
|
194
|
+
microseconds: int = 0,
|
|
195
|
+
milliseconds: int = 0,
|
|
196
|
+
minutes: int = 0,
|
|
197
|
+
hours: int = 0,
|
|
198
|
+
weeks: int = 0) -> datetime:
|
|
199
|
+
return to_datetime(s) + timedelta(days=days, seconds=seconds, microseconds=microseconds,
|
|
200
|
+
milliseconds=milliseconds, minutes=minutes, hours=hours,
|
|
201
|
+
weeks=weeks)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
# 将字符串 s 转化成 date 例如: 2021-02-03
|
|
205
|
+
def to_date(s: Any = None) -> str:
|
|
206
|
+
return str(to_datetime(s))[0:10]
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# 将字符串 s 转化成 date 例如: 20210203
|
|
210
|
+
def to_date_number(s: Any = None) -> str:
|
|
211
|
+
return str(to_datetime(s))[0:10].replace('-', '')
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def get_timestamp(s: Any = None) -> int:
|
|
215
|
+
"""获取 Unix 秒级时间戳"""
|
|
216
|
+
return int(to_datetime(s).timestamp())
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def get_datetime_number_str(s: Any = None,
|
|
220
|
+
length: int = None,
|
|
221
|
+
remove_dz: bool = True,
|
|
222
|
+
) -> str:
|
|
223
|
+
"""获取 datetime , 然后转成字符串, 然后, 只保留数字
|
|
224
|
+
Args:
|
|
225
|
+
s: 输入值,可以是任何类型,如果是None则使用当前时间
|
|
226
|
+
length: 可选参数,指定返回字符串的长度
|
|
227
|
+
remove_dz: 是否去掉时区
|
|
228
|
+
Returns:
|
|
229
|
+
str: 只包含数字的字符串
|
|
230
|
+
"""
|
|
231
|
+
s1 = to_datetime(s)
|
|
232
|
+
digits_only = re.sub(r'\D', '', str(s1))
|
|
233
|
+
# 如果指定了长度,取最后length位
|
|
234
|
+
if length is not None and length > 0:
|
|
235
|
+
return digits_only[-length:] if len(digits_only) > length else digits_only
|
|
236
|
+
if len(digits_only) > 4 and remove_dz:
|
|
237
|
+
digits_only = digits_only[:-4]
|
|
238
|
+
return digits_only
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def get_timestamp_ms(s: Any = None) -> int:
|
|
242
|
+
"""获取 Unix 毫秒级时间戳"""
|
|
243
|
+
return int(to_datetime(s).timestamp() * 1000)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
# 时间加减
|
|
247
|
+
def to_date_add(s: Any = None,
|
|
248
|
+
days: int = 0,
|
|
249
|
+
seconds: int = 0,
|
|
250
|
+
microseconds: int = 0,
|
|
251
|
+
milliseconds: int = 0,
|
|
252
|
+
minutes: int = 0,
|
|
253
|
+
hours: int = 0,
|
|
254
|
+
weeks: int = 0) -> str:
|
|
255
|
+
return str(to_datetime_add(s=s, days=days, seconds=seconds, microseconds=microseconds,
|
|
256
|
+
milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks))[0:10]
|
|
@@ -38,6 +38,38 @@ def get_file(file_path: str = None,
|
|
|
38
38
|
return r_list
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
def get_latest_file(file_path: str = None,
|
|
42
|
+
path_startswith: str = None,
|
|
43
|
+
startswith: str = None,
|
|
44
|
+
path_contain: str = None,
|
|
45
|
+
contain: str = None,
|
|
46
|
+
path_endswith: str = None,
|
|
47
|
+
endswith: str = None,
|
|
48
|
+
full_path: bool = None) -> None | tuple[str, str] | str:
|
|
49
|
+
"""
|
|
50
|
+
按照文件名字排序,获得最新的一个文件
|
|
51
|
+
full_path: 是否返回完整的路径
|
|
52
|
+
"""
|
|
53
|
+
html_list = get_file(file_path=file_path,
|
|
54
|
+
path_startswith=path_startswith,
|
|
55
|
+
startswith=startswith,
|
|
56
|
+
path_contain=path_contain,
|
|
57
|
+
contain=contain,
|
|
58
|
+
sort_asc=False,
|
|
59
|
+
path_endswith=path_endswith,
|
|
60
|
+
endswith=endswith)
|
|
61
|
+
r1 = html_list[-1] if len(html_list) > 0 else None
|
|
62
|
+
if r1 is None:
|
|
63
|
+
return None
|
|
64
|
+
r1_short = r1
|
|
65
|
+
file_sep = '\\' if is_win() else '/'
|
|
66
|
+
if file_sep in r1:
|
|
67
|
+
r1_short = r1.split(file_sep)[-1]
|
|
68
|
+
if full_path is None:
|
|
69
|
+
return r1_short, r1
|
|
70
|
+
return r1 if full_path else r1_short
|
|
71
|
+
|
|
72
|
+
|
|
41
73
|
def get_file_folder(file_name_one: str = None) -> str:
|
|
42
74
|
"""
|
|
43
75
|
返回这个文件的文件夹路径
|
|
@@ -213,6 +245,22 @@ def find_file_by_content(file_path: str = '',
|
|
|
213
245
|
to_log(one_file, e)
|
|
214
246
|
continue
|
|
215
247
|
|
|
248
|
+
|
|
249
|
+
def check_file(file_name: str = None) -> None:
|
|
250
|
+
r"""
|
|
251
|
+
检查文件夹是否存在,不存在,就创建新的
|
|
252
|
+
支持多级目录 , 例如: C:\Users\yangpu\Desktop\study\a\b\c\d\e\f
|
|
253
|
+
"""
|
|
254
|
+
if file_name is None or file_name == '':
|
|
255
|
+
return
|
|
256
|
+
file_sep = '\\' if is_win() else '/'
|
|
257
|
+
f_n = file_name.split(file_sep)
|
|
258
|
+
for i in range(1, len(f_n) + 1):
|
|
259
|
+
# C:\Users\yangpu\Desktop\study\p.t
|
|
260
|
+
p_n = file_sep.join(f_n[0:i])
|
|
261
|
+
if p_n and not os.path.exists(p_n):
|
|
262
|
+
os.mkdir(p_n)
|
|
263
|
+
|
|
216
264
|
# print(get_file_data_line(r'D:\notepad_file\202306\a.txt', 'payout', from_last=False))
|
|
217
265
|
|
|
218
266
|
# file_all = get_file(r'C:\Users\yang\Desktop\ticket\no.use', path_contain='03')
|