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 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.file import *
11
- from upplib.file_text import *
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
@@ -1,6 +1,6 @@
1
1
  from upplib import *
2
2
  from upplib.common_package import *
3
- from upplib.file import *
3
+ from upplib.file_function import *
4
4
 
5
5
  __CONFIG_PATH = '.upp.config'
6
6
 
@@ -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')