tretool 0.2.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.
tretool/timelib.py ADDED
@@ -0,0 +1,518 @@
1
+ import re
2
+ import sys
3
+ import ctypes
4
+
5
+ from typing import overload, Literal
6
+
7
+ class SYSTEMTIME(ctypes.Structure):
8
+ _fields_ = [
9
+ ("wYear", ctypes.c_ushort),
10
+ ("wMonth", ctypes.c_ushort),
11
+ ("wDayOfWeek", ctypes.c_ushort),
12
+ ("wDay", ctypes.c_ushort),
13
+ ("wHour", ctypes.c_ushort),
14
+ ("wMinute", ctypes.c_ushort),
15
+ ("wSecond", ctypes.c_ushort),
16
+ ("wMilliseconds", ctypes.c_ushort),
17
+ ]
18
+
19
+
20
+ def get_timestamp():
21
+ """返回毫秒级时间戳(跨平台)"""
22
+ if sys.platform == "win32":
23
+ # Windows 使用 GetSystemTimeAsFileTime
24
+ libc = ctypes.windll.kernel32
25
+ filetime = ctypes.c_uint64()
26
+ libc.GetSystemTimeAsFileTime(ctypes.byref(filetime))
27
+ return (filetime.value - 116444736000000000) // 10000 # 转毫秒
28
+ else:
29
+ # Unix 使用 gettimeofday
30
+ class Timeval(ctypes.Structure):
31
+ _fields_ = [("tv_sec", ctypes.c_long), ("tv_usec", ctypes.c_long)]
32
+ libc = ctypes.CDLL(None)
33
+ tv = Timeval()
34
+ libc.gettimeofday(ctypes.byref(tv), None)
35
+ return tv.tv_sec * 1000 + tv.tv_usec // 1000 # 毫秒
36
+
37
+
38
+ def get_now_by_fmt(fmt: str = '%YYYY-%mm-%dd %HH:%MM:%SS.%fff') -> str:
39
+ """
40
+ 获取当前时间(支持自定义格式,包含毫秒),仅适用于 Windows
41
+ 支持的格式符:
42
+ %Y / %YYYY - 年(4位)
43
+ %YY - 年(2位)
44
+ %m / %mm - 月(01-12)
45
+ %d / %dd - 日(01-31)
46
+ %H / %HH - 时(00-23)
47
+ %M / %MM - 分(00-59)
48
+ %S / %SS - 秒(00-59)
49
+ %f / %ff / %fff - 毫秒(1-3位)
50
+ """
51
+ kernel32 = ctypes.windll.kernel32
52
+ time = SYSTEMTIME()
53
+ kernel32.GetLocalTime(ctypes.byref(time))
54
+
55
+ # 替换格式化字符串(按长度从长到短处理,避免替换冲突)
56
+ formatted = fmt
57
+ replacements = [
58
+ ("%YYYY", f"{time.wYear:04d}"),
59
+ ("%YYY", f"{time.wYear % 1000:03d}"),
60
+ ("%YY", f"{time.wYear % 100:02d}"),
61
+ ("%Y", f"{time.wYear:01d}"),
62
+ ("%mm", f"{time.wMonth:02d}"),
63
+ ("%m", f"{time.wMonth:01d}"),
64
+ ("%dd", f"{time.wDay:02d}"),
65
+ ("%d", f"{time.wDay:01d}"),
66
+ ("%HH", f"{time.wHour:02d}"),
67
+ ("%H", f"{time.wHour:01d}"),
68
+ ("%MM", f"{time.wMinute:02d}"),
69
+ ("%M", f"{time.wMinute:01d}"),
70
+ ("%SS", f"{time.wSecond:02d}"),
71
+ ("%S", f"{time.wSecond:01d}"),
72
+ ("%fff", f"{time.wMilliseconds:03d}"),
73
+ ("%ff", f"{time.wMilliseconds // 10:02d}"),
74
+ ("%f", f"{time.wMilliseconds // 100:01d}")
75
+ ]
76
+
77
+ for pattern, replacement in replacements:
78
+ formatted = formatted.replace(pattern, replacement)
79
+
80
+ return formatted
81
+
82
+
83
+ def get_now_by_systemtime(
84
+ wYear: bool = True,
85
+ wMonth: bool = True,
86
+ wDay: bool = True,
87
+ wHour: bool = True,
88
+ wMinute: bool = True,
89
+ wSecond: bool = True,
90
+ wMilliseconds: bool = True
91
+ ) -> SYSTEMTIME:
92
+ """
93
+ 获取当前时间的 SYSTEMTIME 对象(可选字段)\n
94
+ 参数:
95
+ 参数:指定需要包含的字段
96
+ 返回:
97
+ SYSTEMTIME 结构体
98
+ """
99
+ kernel32 = ctypes.windll.kernel32
100
+ time = SYSTEMTIME()
101
+ kernel32.GetLocalTime(ctypes.byref(time))
102
+
103
+ result = SYSTEMTIME()
104
+ if wYear: result.wYear = time.wYear
105
+ if wMonth: result.wMonth = time.wMonth
106
+ if wDay: result.wDay = time.wDay
107
+ if wHour: result.wHour = time.wHour
108
+ if wMinute: result.wMinute = time.wMinute
109
+ if wSecond: result.wSecond = time.wSecond
110
+ if wMilliseconds: result.wMilliseconds = time.wMilliseconds
111
+ return result
112
+
113
+
114
+ def parse_time_systemtime(time_str: str, fmt: str) -> SYSTEMTIME:
115
+ """
116
+ 将时间字符串解析为 SYSTEMTIME 结构(支持毫秒)
117
+
118
+ 参数:
119
+ time_str: 时间字符串
120
+ fmt: 格式字符串
121
+
122
+ 返回:
123
+ SYSTEMTIME 结构体(包含毫秒)
124
+
125
+ 异常:
126
+ ValueError: 当时间字符串与格式不匹配或包含无效值时
127
+ """
128
+ time = SYSTEMTIME()
129
+
130
+ # 初始化默认值
131
+ time.wYear = 0
132
+ time.wMonth = 1
133
+ time.wDay = 1
134
+ time.wHour = 0
135
+ time.wMinute = 0
136
+ time.wSecond = 0
137
+ time.wMilliseconds = 0
138
+
139
+ # 构建正则表达式模式(添加毫秒支持)
140
+ format_patterns = {
141
+ '%YYYY': r'(?P<year>\d{4})',
142
+ '%Y': r'(?P<year>\d{1,4})',
143
+ '%yy': r'(?P<year>\d{2})',
144
+ '%y': r'(?P<year>\d{1,2})',
145
+ '%mm': r'(?P<month>0[1-9]|1[0-2])',
146
+ '%m': r'(?P<month>[1-9]|1[0-2])',
147
+ '%dd': r'(?P<day>0[1-9]|[12]\d|3[01])',
148
+ '%d': r'(?P<day>[1-9]|[12]\d|3[01])',
149
+ '%HH': r'(?P<hour>[01]\d|2[0-3])',
150
+ '%H': r'(?P<hour>\d|1\d|2[0-3])',
151
+ '%MM': r'(?P<minute>[0-5]\d)',
152
+ '%M': r'(?P<minute>\d|[0-5]\d)',
153
+ '%SS': r'(?P<second>[0-5]\d)',
154
+ '%S': r'(?P<second>\d|[0-5]\d)',
155
+ '%fff': r'(?P<millis>\d{3})',
156
+ '%ff': r'(?P<millis>\d{2})',
157
+ '%f': r'(?P<millis>\d{1})'
158
+ }
159
+
160
+ # 转义fmt中的特殊字符,但保留格式说明符
161
+ pattern = re.escape(fmt)
162
+ for fmt_code, regex in format_patterns.items():
163
+ pattern = pattern.replace(re.escape(fmt_code), regex)
164
+
165
+ # 匹配时间字符串
166
+ match = re.fullmatch(pattern, time_str)
167
+ if not match:
168
+ raise ValueError(f"时间字符串 '{time_str}' 与格式 '{fmt}' 不匹配")
169
+
170
+ # 提取并验证各字段
171
+ groups = match.groupdict()
172
+
173
+ try:
174
+ if 'year' in groups and groups['year']:
175
+ year = int(groups['year'])
176
+ if year < 0 or year > 9999:
177
+ raise ValueError("年份必须在0-9999范围内")
178
+ if len(groups['year']) <= 2: # 2位年份处理
179
+ current_year = get_now_by_fmt("%YYYY")
180
+ century = int(current_year[:2]) * 100
181
+ year = century + year
182
+ if year > int(current_year) + 50: # 处理跨世纪
183
+ year -= 100
184
+ time.wYear = year
185
+
186
+ if 'month' in groups and groups['month']:
187
+ month = int(groups['month'])
188
+ if not 1 <= month <= 12:
189
+ raise ValueError("月份必须在1-12范围内")
190
+ time.wMonth = month
191
+
192
+ if 'day' in groups and groups['day']:
193
+ day = int(groups['day'])
194
+ max_day = days_in_month(time.wYear, time.wMonth)
195
+ if not 1 <= day <= max_day:
196
+ raise ValueError(f"日期无效,{time.wYear}年{time.wMonth}月最多有{max_day}天")
197
+ time.wDay = day
198
+
199
+ if 'hour' in groups and groups['hour']:
200
+ hour = int(groups['hour'])
201
+ if not 0 <= hour <= 23:
202
+ raise ValueError("小时必须在0-23范围内")
203
+ time.wHour = hour
204
+
205
+ if 'minute' in groups and groups['minute']:
206
+ minute = int(groups['minute'])
207
+ if not 0 <= minute <= 59:
208
+ raise ValueError("分钟必须在0-59范围内")
209
+ time.wMinute = minute
210
+
211
+ if 'second' in groups and groups['second']:
212
+ second = int(groups['second'])
213
+ if not 0 <= second <= 59:
214
+ raise ValueError("秒数必须在0-59范围内")
215
+ time.wSecond = second
216
+
217
+ if 'millis' in groups and groups['millis']:
218
+ millis = int(groups['millis'])
219
+ # 根据格式长度调整毫秒值
220
+ if fmt.count('f') == 1: # %f
221
+ millis *= 100
222
+ elif fmt.count('f') == 2: # %ff
223
+ millis *= 10
224
+ if not 0 <= millis <= 999:
225
+ raise ValueError("毫秒必须在0-999范围内")
226
+ time.wMilliseconds = millis
227
+
228
+ except ValueError as e:
229
+ raise ValueError(f"无效的时间值: {e}") from e
230
+
231
+ return time
232
+
233
+
234
+ def is_leap_year(year: int) -> bool:
235
+ """判断是否为闰年"""
236
+ return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
237
+
238
+
239
+ def days_in_month(year: int, month: int) -> int:
240
+ """返回某年某月的天数"""
241
+ if month > 12:
242
+ raise ValueError('月份不能大于12')
243
+ if month == 2:
244
+ return 29 if is_leap_year(year) else 28
245
+ elif month in [4, 6, 9, 11]:
246
+ return 30
247
+ else:
248
+ return 31
249
+
250
+
251
+ @overload
252
+ def sub_time(start: str, end: str, fmt: str = "%YYYY-%mm-%dd %HH:%MM:%SS.%fff") -> dict:
253
+ """
254
+ 计算两个时间的差值(考虑月份、闰年、时间进位)
255
+ 返回格式:{"days": X, "hours": X, "minutes": X, "seconds": X, "ms": X}
256
+ """
257
+ ...
258
+
259
+ @overload
260
+ def sub_time(start: str, end: SYSTEMTIME, fmt: str = "%YYYY-%mm-%dd %HH:%MM:%SS.%fff") -> dict:
261
+ """
262
+ 计算两个时间的差值(考虑月份、闰年、时间进位)
263
+ 返回格式:{"days": X, "hours": X, "minutes": X, "seconds": X, "ms": X}
264
+ """
265
+ ...
266
+
267
+ @overload
268
+ def sub_time(start: SYSTEMTIME, end: str, fmt: str = "%YYYY-%mm-%dd %HH:%MM:%SS.%fff") -> dict:
269
+ """
270
+ 计算两个时间的差值(考虑月份、闰年、时间进位)
271
+ 返回格式:{"days": X, "hours": X, "minutes": X, "seconds": X, "ms": X}
272
+ """
273
+ ...
274
+
275
+ @overload
276
+ def sub_time(start: SYSTEMTIME, end: SYSTEMTIME, fmt: str = "%YYYY-%mm-%dd %HH:%MM:%SS.%fff") -> dict:
277
+ """
278
+ 计算两个时间的差值(考虑月份、闰年、时间进位)
279
+ 返回格式:{"days": X, "hours": X, "minutes": X, "seconds": X, "ms": X}
280
+ """
281
+ ...
282
+
283
+ def sub_time(start: str|SYSTEMTIME, end: str|SYSTEMTIME, fmt: str = "%YYYY-%mm-%dd %HH:%MM:%SS.%fff") -> dict:
284
+ """
285
+ 计算两个时间的差值(考虑月份、闰年、时间进位)
286
+ 返回格式:{"days": X, "hours": X, "minutes": X, "seconds": X, "ms": X}
287
+ """
288
+ if isinstance(start, str):
289
+ start_time = parse_time_systemtime(start, fmt)
290
+ else:
291
+ start_time = start
292
+
293
+ if isinstance(end, str):
294
+ end_time = parse_time_systemtime(end, fmt)
295
+ else:
296
+ end_time = end
297
+
298
+ # 计算总毫秒数差
299
+ total_ms = 0
300
+
301
+ # 计算年份差(转换为天数)
302
+ for year in range(start_time.wYear, end_time.wYear):
303
+ total_ms += (366 if is_leap_year(year) else 365) * 86400 * 1000
304
+
305
+ # 计算月份差(转换为天数)
306
+ if end_time.wYear == start_time.wYear:
307
+ month_range = range(start_time.wMonth, end_time.wMonth)
308
+ else:
309
+ month_range = list(range(start_time.wMonth, 13)) + list(range(1, end_time.wMonth))
310
+
311
+ for month in month_range:
312
+ year = start_time.wYear if month >= start_time.wMonth else end_time.wYear
313
+ total_ms += days_in_month(year, month) * 86400 * 1000
314
+
315
+ # 计算天数差
316
+ total_ms += (end_time.wDay - start_time.wDay) * 86400 * 1000
317
+
318
+ # 计算时、分、秒差
319
+ total_ms += (end_time.wHour - start_time.wHour) * 3600 * 1000
320
+ total_ms += (end_time.wMinute - start_time.wMinute) * 60 * 1000
321
+ total_ms += (end_time.wSecond - start_time.wSecond) * 1000
322
+ total_ms += (end_time.wMilliseconds - start_time.wMilliseconds)
323
+
324
+ # 转换为天数、小时、分钟、秒、毫秒
325
+ days = total_ms // (86400 * 1000)
326
+ remaining_ms = total_ms % (86400 * 1000)
327
+ hours = remaining_ms // (3600 * 1000)
328
+ remaining_ms %= (3600 * 1000)
329
+ minutes = remaining_ms // (60 * 1000)
330
+ remaining_ms %= (60 * 1000)
331
+ seconds = remaining_ms // 1000
332
+ ms = remaining_ms % 1000
333
+
334
+ return {
335
+ "days": days,
336
+ "hours": hours,
337
+ "minutes": minutes,
338
+ "seconds": seconds,
339
+ "ms": ms
340
+ }
341
+
342
+
343
+ def sleep(duration: int | float, unit: Literal["minutes", "seconds", "milliseconds"] = "seconds") -> None:
344
+ """
345
+ 实现精确休眠,仅适用于Windows\n
346
+ 参数:
347
+ duration: 时间长度
348
+ unit: 时间单位("minutes"/"seconds"/"milliseconds")
349
+ """
350
+ kernel32 = ctypes.windll.kernel32
351
+
352
+ # 根据单位转换为毫秒
353
+ if unit == "minutes":
354
+ ms = int(duration * 60 * 1000)
355
+ elif unit == "seconds":
356
+ ms = int(duration * 1000)
357
+ else: # milliseconds
358
+ ms = int(duration)
359
+
360
+ kernel32.Sleep(ms)
361
+
362
+
363
+ class Counter:
364
+ def __init__(self, default_count: int = 0):
365
+ """
366
+ 计数器类
367
+
368
+ 参数:
369
+ default_count: 初始计数值,默认为0
370
+ """
371
+ self.count = default_count
372
+
373
+ def add(self, value: int = 1) -> None:
374
+ """
375
+ 增加计数值
376
+
377
+ 参数:
378
+ value: 要增加的值,默认为1
379
+ """
380
+ self.count += value
381
+
382
+ def reset(self, new_value: int = 0) -> None:
383
+ """
384
+ 重置计数器
385
+
386
+ 参数:
387
+ new_value: 重置后的值,默认为0
388
+ """
389
+ self.count = new_value
390
+
391
+ def __call__(self, add_value: int = 1) -> None:
392
+ """
393
+ 使实例可调用,等同于add()方法
394
+
395
+ 参数:
396
+ add_value: 要增加的值,默认为1
397
+ """
398
+ self.add(add_value)
399
+
400
+ def __eq__(self, other) -> bool:
401
+ """
402
+ 比较两个计数器的值
403
+
404
+ 参数:
405
+ other: 可以是Counter实例或整数
406
+ """
407
+ if isinstance(other, Counter):
408
+ return self.count == other.count
409
+ elif isinstance(other, int):
410
+ return self.count == other
411
+ return NotImplemented
412
+
413
+ def __str__(self) -> str:
414
+ """
415
+ 字符串表示
416
+ """
417
+ return f"Counter: var count is {self.count}"
418
+
419
+ def __repr__(self) -> str:
420
+ """
421
+ 官方字符串表示
422
+ """
423
+ return f"Counter(count={self.count})"
424
+
425
+ def __hash__(self):
426
+ return hash(f'Counter(count={self.count})')
427
+
428
+ def __ne__(self, other):
429
+ if isinstance(other, Counter):
430
+ return self.count != other.count
431
+ elif isinstance(other, int):
432
+ return self.count != other
433
+ return NotImplemented
434
+
435
+ def __add__(self, value) -> 'Counter':
436
+ self.count += value
437
+ return self
438
+
439
+ def __sub__(self, value: int) -> 'Counter':
440
+ self.count -= value
441
+ return self
442
+
443
+ @property
444
+ def value(self) -> int:
445
+ """
446
+ 获取当前计数值
447
+ """
448
+ return self.count
449
+
450
+
451
+ class Timer:
452
+ def __init__(self, auto_start=False):
453
+ """
454
+ 初始化计时器\n
455
+ :param auto_start: 是否自动开始计时(默认False)
456
+ """
457
+ self.start_time = 0
458
+ self.end_time = 0
459
+ self.time_sub = 0
460
+ if auto_start:
461
+ self.start_timer()
462
+
463
+
464
+ def __repr__(self):
465
+ """返回可用于重新创建对象的官方字符串表示"""
466
+ return (f"Timer(start_time={self.start_time}, "
467
+ f"end_time={self.end_time}, "
468
+ f"elapsed={self.elapsed_time()})")
469
+
470
+
471
+ def __str__(self):
472
+ """返回用户友好的字符串表示"""
473
+ status = "运行中" if self.end_time == 0 and self.start_time != 0 else "已停止"
474
+ return (f"计时器状态: {status}\n"
475
+ f"开始时间: {self.start_time}\n"
476
+ f"结束时间: {self.end_time}\n"
477
+ f"已耗时: {self.elapsed_time()}秒")
478
+
479
+
480
+ def start_timer(self):
481
+ """启动/重启计时器"""
482
+ self.reset()
483
+ self.start_time = get_timestamp()
484
+ return self.start_time
485
+
486
+
487
+ def end_timer(self):
488
+ """停止计时器"""
489
+ if self.start_time == 0:
490
+ raise RuntimeError("计时器尚未启动")
491
+ self.end_time = get_timestamp()
492
+ return self.end_time
493
+
494
+
495
+ def elapsed_time(self):
496
+ """获取当前耗时(自动处理未停止情况)"""
497
+ if self.start_time == 0:
498
+ return 0
499
+ current_end = self.end_time if self.end_time != 0 else get_timestamp()
500
+ self.time_sub = current_end - self.start_time
501
+ return self.time_sub
502
+
503
+
504
+ def end_get_time(self):
505
+ """停止计时并返回最终耗时"""
506
+ if self.start_time == 0:
507
+ raise RuntimeError("计时器未启动")
508
+ if self.end_time == 0:
509
+ self.end_timer()
510
+ return self.time_sub
511
+
512
+
513
+ def reset(self):
514
+ """完全重置计时器"""
515
+ self.start_time = 0
516
+ self.end_time = 0
517
+ self.time_sub = 0
518
+
@@ -0,0 +1 @@
1
+ from . import pdf