qrpa 1.1.33__py3-none-any.whl → 1.1.35__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.

Potentially problematic release.


This version of qrpa might be problematic. Click here for more details.

qrpa/time_utils.py CHANGED
@@ -1,882 +1,882 @@
1
- """
2
- 时间工具模块
3
- 提供各种时间相关的工具函数,包括日期获取、格式化、转换、计算等功能
4
- """
5
-
6
- import os
7
- import calendar
8
- from datetime import date, datetime, timedelta, timezone
9
- from typing import Optional, Tuple, List, Union
10
-
11
- class TimeUtils:
12
- """时间工具类,提供各种时间相关的静态方法"""
13
-
14
- # ==================== 当前时间获取 ====================
15
-
16
- @staticmethod
17
- def get_current_date() -> str:
18
- """获取当前日期,格式为 YYYYMMDD"""
19
- return datetime.now().strftime('%Y%m%d')
20
-
21
- @staticmethod
22
- def get_current_datetime() -> str:
23
- """获取当前日期时间,格式为 YYYYMMDDHHMMSS"""
24
- return datetime.now().strftime('%Y%m%d%H%M%S')
25
-
26
- @staticmethod
27
- def current_datetime() -> str:
28
- """获取当前日期时间,格式为 YYYY-MM-DD HH:MM:SS"""
29
- return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
30
-
31
- @staticmethod
32
- def today_date() -> str:
33
- """获取今天的日期,格式为 YYYY-MM-DD"""
34
- return datetime.now().strftime('%Y-%m-%d')
35
-
36
- @staticmethod
37
- def today_date_hour() -> str:
38
- """获取今天的日期和小时,格式为 YYYY-MM-DD_HH"""
39
- return datetime.now().strftime('%Y-%m-%d_%H')
40
-
41
- @staticmethod
42
- def get_current_year() -> int:
43
- """获取当前年份"""
44
- return datetime.now().year
45
-
46
- @staticmethod
47
- def get_current_month() -> int:
48
- """获取当前月份(1-12)"""
49
- return datetime.now().month
50
-
51
- @staticmethod
52
- def get_current_year_range() -> Tuple[str, str]:
53
- """获取当前年份的开始和结束日期"""
54
- current_year = datetime.now().year
55
- start_date = datetime(current_year, 1, 1).strftime('%Y-%m-%d')
56
- end_date = datetime(current_year, 12, 31).strftime('%Y-%m-%d')
57
- return start_date, end_date
58
-
59
- # ==================== 相对日期获取 ====================
60
-
61
- @staticmethod
62
- def get_yesterday(dt: Optional[str] = None) -> str:
63
- """
64
- 获取昨天的日期
65
-
66
- Args:
67
- dt: 可选的基础日期,格式为 YYYYMMDD,默认为今天
68
-
69
- Returns:
70
- 昨天的日期,格式为 YYYY-MM-DD
71
- """
72
- if dt is None:
73
- dt = datetime.now()
74
- else:
75
- dt = datetime.strptime(dt, "%Y%m%d")
76
- yesterday = dt - timedelta(days=1)
77
- return yesterday.strftime("%Y-%m-%d")
78
-
79
- @staticmethod
80
- def before_yesterday() -> str:
81
- """获取前天的日期"""
82
- return (datetime.now().date() - timedelta(days=2)).strftime("%Y-%m-%d")
83
-
84
- @staticmethod
85
- def tomorrow_date() -> str:
86
- """获取明天的日期"""
87
- return (datetime.now().date() + timedelta(days=1)).strftime("%Y-%m-%d")
88
-
89
- @staticmethod
90
- def get_last_month() -> int:
91
- """获取上个月的月份"""
92
- today = datetime.today()
93
- last_month = today.month - 1 if today.month > 1 else 12
94
- return last_month
95
-
96
- @staticmethod
97
- def get_last_two_month() -> int:
98
- """获取上上个月的月份"""
99
- today = datetime.today()
100
- # 计算上上个月:当前月份减2
101
- last_two_month = today.month - 2
102
- # 处理跨年情况
103
- if last_two_month < 1:
104
- last_two_month += 12
105
- return last_two_month
106
-
107
- # ==================== 日期范围计算 ====================
108
-
109
- @staticmethod
110
- def get_past_7_days_range(start_from: Optional[str] = None, format_str: str = '%Y-%m-%d') -> Tuple[str, str,]:
111
- """
112
- 获取过去7天的日期范围(包括结束日,共7天)
113
-
114
- Args:
115
- start_from: 可选的起始参考日期(格式 'YYYY-MM-DD'),默认以今天为起点
116
-
117
- Returns:
118
- (start_date_str, end_date_str) 日期范围元组
119
-
120
- Example:
121
- >>> get_past_7_days_range('2025-07-02')
122
- ('2025-06-25', '2025-07-01')
123
- """
124
- if start_from:
125
- try:
126
- base_date = datetime.strptime(start_from, '%Y-%m-%d')
127
- except ValueError:
128
- raise ValueError("start_from 格式必须是 'YYYY-MM-DD'")
129
- else:
130
- base_date = datetime.today()
131
-
132
- end_date = base_date - timedelta(days=1) # 默认昨天为结束
133
- start_date = end_date - timedelta(days=6) # 往前推6天为开始
134
-
135
- return start_date.strftime(format_str), end_date.strftime(format_str)
136
-
137
- @staticmethod
138
- def get_past_7_days_range_format(start_from: Optional[str] = None, format_str: str = '%Y-%m-%d') -> Tuple[str, str]:
139
- """
140
- 获取过去7天的日期范围(包括结束日,共7天),支持自定义格式
141
-
142
- Args:
143
- start_from: 可选的起始参考日期(格式 'YYYY-MM-DD'),默认以今天为起点
144
- format_str: 日期格式字符串
145
-
146
- Returns:
147
- (start_date_str, end_date_str) 日期范围元组
148
- """
149
- if start_from:
150
- try:
151
- base_date = datetime.strptime(start_from, '%Y-%m-%d')
152
- except ValueError:
153
- raise ValueError("start_from 格式必须是 'YYYY-MM-DD'")
154
- else:
155
- base_date = datetime.today()
156
-
157
- end_date = base_date - timedelta(days=1) # 默认昨天为结束
158
- start_date = end_date - timedelta(days=6) # 往前推6天为开始
159
-
160
- return start_date.strftime(format_str), end_date.strftime(format_str)
161
-
162
- @staticmethod
163
- def get_month_first_day(start_from: Optional[str] = None, format_str: str = '%Y-%m-%d') -> str:
164
- """
165
- 获取某月的第一天
166
-
167
- Args:
168
- start_from: 参考日期,格式为'YYYY-MM-DD',默认使用今天
169
- format_str: 返回的日期格式,默认是'%Y-%m-%d'
170
-
171
- Returns:
172
- 指定格式的某月第一天日期字符串
173
-
174
- Example:
175
- >>> get_month_first_day('2025-07-02')
176
- '2025-07-01'
177
- """
178
- if start_from:
179
- try:
180
- base_date = datetime.strptime(start_from, '%Y-%m-%d')
181
- except ValueError:
182
- raise ValueError("start_from 格式必须是 'YYYY-MM-DD'")
183
- else:
184
- base_date = datetime.today()
185
-
186
- # 获取当月第一天
187
- first_day = base_date.replace(day=1)
188
- return first_day.strftime(format_str)
189
-
190
- @staticmethod
191
- def get_past_nth_day(n: int, start_from: Optional[str] = None, format_str: str = '%Y-%m-%d') -> str:
192
- """
193
- 获取过去第n天的日期
194
-
195
- Args:
196
- n: 获取过去第n天的日期(n=1 表示昨天,n=2 表示前天,以此类推)
197
- start_from: 可选的起始参考日期(格式 'YYYY-MM-DD'),默认以今天为起点
198
-
199
- Returns:
200
- 'YYYY-MM-DD' 格式的日期
201
-
202
- Example:
203
- >>> get_past_nth_day(29, '2025-07-02')
204
- '2025-06-03'
205
- """
206
- if start_from:
207
- try:
208
- base_date = datetime.strptime(start_from, '%Y-%m-%d')
209
- except ValueError:
210
- raise ValueError("start_from 格式必须是 'YYYY-MM-DD'")
211
- else:
212
- base_date = datetime.today()
213
-
214
- past_date = base_date - timedelta(days=n)
215
- return past_date.strftime(format_str)
216
-
217
- @staticmethod
218
- def get_past_n_days_list(n: int, start_from: Optional[str] = None) -> List[str]:
219
- """
220
- 获取过去n天的日期列表,从最旧到最近的日期
221
-
222
- Args:
223
- n: 获取过去多少天
224
- start_from: 可选的起始参考日期(格式 'YYYY-MM-DD'),默认以今天为起点
225
-
226
- Returns:
227
- ['YYYY-MM-DD', ..., 'YYYY-MM-DD'],从旧到新排序
228
-
229
- Example:
230
- >>> get_past_n_days_list(7, '2025-07-02')
231
- ['2025-07-01', '2025-06-30', '2025-06-29', '2025-06-28', '2025-06-27', '2025-06-26', '2025-06-25']
232
- """
233
- if start_from:
234
- try:
235
- base_date = datetime.strptime(start_from, '%Y-%m-%d')
236
- except ValueError:
237
- raise ValueError("start_from 格式必须是 'YYYY-MM-DD'")
238
- else:
239
- base_date = datetime.today()
240
-
241
- return [
242
- (base_date - timedelta(days=i)).strftime('%Y-%m-%d')
243
- for i in range(1, n + 1)
244
- ]
245
-
246
- @staticmethod
247
- def get_past_7_days_list(start_from: Optional[str] = None) -> List[str]:
248
- """
249
- 获取过去7天的日期列表(不包含 start_from 当天),共7天
250
-
251
- Args:
252
- start_from: 可选的起始参考日期(格式 'YYYY-MM-DD'),默认以今天为起点
253
-
254
- Returns:
255
- ['YYYY-MM-DD', ..., 'YYYY-MM-DD'],从旧到新排序
256
- """
257
- if start_from:
258
- try:
259
- base_date = datetime.strptime(start_from, '%Y-%m-%d')
260
- except ValueError:
261
- raise ValueError("start_from 格式必须是 'YYYY-MM-DD'")
262
- else:
263
- base_date = datetime.today()
264
-
265
- return [
266
- (base_date - timedelta(days=i)).strftime('%Y-%m-%d')
267
- for i in range(1, 8)
268
- ]
269
-
270
- @staticmethod
271
- def date_range(start_date: str, end_date: str) -> List[str]:
272
- """
273
- 生成两个日期之间的日期列表
274
-
275
- Args:
276
- start_date: 开始日期,格式为YYYY-MM-DD
277
- end_date: 结束日期,格式为YYYY-MM-DD
278
-
279
- Returns:
280
- 包含两个日期之间所有日期的列表,日期格式为YYYY-MM-DD
281
-
282
- Raises:
283
- ValueError: 当开始日期大于结束日期时
284
- """
285
- start = datetime.strptime(start_date, "%Y-%m-%d")
286
- end = datetime.strptime(end_date, "%Y-%m-%d")
287
-
288
- if start > end:
289
- raise ValueError("开始日期不能大于结束日期")
290
-
291
- date_list = []
292
- current_date = start
293
- while current_date <= end:
294
- date_list.append(current_date.strftime("%Y-%m-%d"))
295
- current_date += timedelta(days=1)
296
-
297
- return date_list
298
-
299
- @staticmethod
300
- def get_dates_from_first_of_month_to_yesterday() -> List[str]:
301
- """获取从本月第一天到昨天的日期列表
302
- 如果今天是本月第一天,则返回上个月的日期列表
303
- """
304
- today = datetime.today()
305
- yesterday = today - timedelta(days=1)
306
-
307
- # 如果今天是本月第一天,取上个月
308
- if today.day == 1:
309
- # 找到上个月最后一天
310
- last_month_last_day = today - timedelta(days=1)
311
- # 上个月第一天
312
- first_day_of_last_month = last_month_last_day.replace(day=1)
313
- start_date = first_day_of_last_month
314
- end_date = last_month_last_day
315
- else:
316
- start_date = today.replace(day=1)
317
- end_date = yesterday
318
-
319
- date_list = []
320
- current_date = start_date
321
- while current_date <= end_date:
322
- date_list.append(current_date.strftime('%Y-%m-%d'))
323
- current_date += timedelta(days=1)
324
-
325
- return date_list
326
-
327
- # ==================== 月份相关 ====================
328
-
329
- @staticmethod
330
- def get_last_month_range() -> Tuple[str, str]:
331
- """获取上个月的第一天和最后一天"""
332
- today = datetime.today()
333
- last_month = today.month - 1 if today.month > 1 else 12
334
- year = today.year if today.month > 1 else today.year - 1
335
-
336
- first_day = datetime(year, last_month, 1)
337
- last_day = datetime(year, last_month, calendar.monthrange(year, last_month)[1])
338
-
339
- return first_day.strftime("%Y-%m-%d"), last_day.strftime("%Y-%m-%d")
340
-
341
- @staticmethod
342
- def get_last_two_month_range() -> Tuple[str, str]:
343
- """获取上上个月的第一天和最后一天"""
344
- today = datetime.today()
345
- # 计算上上个月
346
- last_two_month = today.month - 2
347
- year = today.year
348
-
349
- # 处理跨年情况
350
- if last_two_month < 1:
351
- last_two_month += 12
352
- year -= 1
353
-
354
- first_day = datetime(year, last_two_month, 1)
355
- last_day = datetime(year, last_two_month, calendar.monthrange(year, last_two_month)[1])
356
-
357
- return first_day.strftime("%Y-%m-%d"), last_day.strftime("%Y-%m-%d")
358
-
359
- @staticmethod
360
- def get_last_month_range_time_str() -> Tuple[str, str]:
361
- """获取上个月第一天和最后一天的时间字符串"""
362
- today = datetime.today()
363
- last_month = today.month - 1 if today.month > 1 else 12
364
- year = today.year if today.month > 1 else today.year - 1
365
-
366
- first_day = datetime(year, last_month, 1, 0, 0, 0)
367
- last_day = datetime(year, last_month, calendar.monthrange(year, last_month)[1], 23, 59, 59)
368
-
369
- start_time_str = first_day.strftime("%Y-%m-%d %H:%M:%S")
370
- end_time_str = last_day.strftime("%Y-%m-%d %H:%M:%S")
371
-
372
- return start_time_str, end_time_str
373
-
374
- @staticmethod
375
- def get_last_month_range_time() -> Tuple[int, int]:
376
- """获取上个月第一天和最后一天的毫秒级时间戳"""
377
- today = datetime.today()
378
- last_month = today.month - 1 if today.month > 1 else 12
379
- year = today.year if today.month > 1 else today.year - 1
380
-
381
- first_day = datetime(year, last_month, 1, 0, 0, 0)
382
- last_day = datetime(year, last_month, calendar.monthrange(year, last_month)[1], 23, 59, 59, 0)
383
-
384
- start_timestamp = int(first_day.timestamp() * 1000)
385
- end_timestamp = int(last_day.timestamp() * 1000)
386
-
387
- return start_timestamp, end_timestamp
388
-
389
- @staticmethod
390
- def get_year_range_time(year=2024):
391
- """获取某一整年的第一天和最后一天的毫秒级时间戳"""
392
- first_day = datetime(year, 1, 1, 0, 0, 0)
393
- last_day = datetime(year, 12, 31, 0, 0, 0, 0)
394
-
395
- start_timestamp = int(first_day.timestamp() * 1000)
396
- end_timestamp = int(last_day.timestamp() * 1000)
397
-
398
- return start_timestamp, end_timestamp
399
-
400
- @staticmethod
401
- def is_in_month(time_str: str, month: int, fmt: str = "%Y-%m-%d") -> bool:
402
- """
403
- 判断时间字符串是否在指定月份
404
-
405
- Args:
406
- time_str: 时间字符串
407
- month: 月份(1-12)
408
- fmt: 时间格式
409
-
410
- Returns:
411
- 如果时间在指定月份返回True,否则返回False
412
- """
413
- try:
414
- dt = datetime.strptime(time_str, fmt)
415
- return dt.month == month
416
- except ValueError:
417
- return False
418
-
419
- # ==================== 星期相关 ====================
420
-
421
- @staticmethod
422
- def get_week_num() -> int:
423
- """获取当前是第几周"""
424
- today = date.today()
425
- week_num = today.isocalendar()[1] # 返回 (year, week_num, weekday)
426
- return week_num
427
-
428
- @staticmethod
429
- def get_chinese_weekday(date_str: str) -> str:
430
- """
431
- 根据输入的日期字符串返回中文星期几
432
-
433
- Args:
434
- date_str: 格式为'YYYY-MM-DD'的日期字符串
435
-
436
- Returns:
437
- 中文星期几,如'星期一'
438
-
439
- Example:
440
- >>> get_chinese_weekday('2025-04-15')
441
- '星期二'
442
- """
443
- try:
444
- date_obj = datetime.strptime(date_str, '%Y-%m-%d')
445
- weekday_num = date_obj.weekday()
446
- weekday_cn = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
447
- return weekday_cn[weekday_num]
448
- except ValueError as e:
449
- raise ValueError(f"日期格式错误,请输入'YYYY-MM-DD'格式的日期字符串。错误详情: {str(e)}")
450
-
451
- @staticmethod
452
- def get_weekday_name(date_str: str) -> str:
453
- """获取中文星期名称(简短格式)"""
454
- weekdays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
455
- date_obj = datetime.strptime(date_str, '%Y-%m-%d')
456
- return weekdays[date_obj.weekday()]
457
-
458
- # ==================== 时间段相关 ====================
459
-
460
- @staticmethod
461
- def get_period() -> str:
462
- """获取当前时间段(上午/下午/晚上)"""
463
- hour = datetime.now().hour
464
- if 5 <= hour < 12:
465
- return "上午"
466
- elif 12 <= hour < 18:
467
- return "下午"
468
- else:
469
- return "晚上"
470
-
471
- @staticmethod
472
- def get_period2() -> str:
473
- """获取当前时间段(AM/PM)"""
474
- now = datetime.now()
475
- period = now.strftime("%p") # 返回AM或者PM
476
- return period
477
-
478
- # ==================== 时间戳转换 ====================
479
-
480
- @staticmethod
481
- def convert_timestamp_to_str(timestamp_ms: Optional[int]) -> str:
482
- """
483
- 将毫秒时间戳转换为字符串
484
-
485
- Args:
486
- timestamp_ms: 毫秒时间戳
487
-
488
- Returns:
489
- 格式化的时间字符串,如果输入为None则返回'-'
490
- """
491
- if timestamp_ms is None:
492
- return '-'
493
- timestamp_s = int(timestamp_ms) / 1000
494
- dt = datetime.fromtimestamp(timestamp_s)
495
- return dt.strftime('%Y-%m-%d %H:%M:%S')
496
-
497
- @staticmethod
498
- def convert_timestamp_to_date(timestamp_ms: Union[int, float]) -> str:
499
- """
500
- 将毫秒时间戳转换为日期字符串
501
-
502
- Args:
503
- timestamp_ms: 毫秒时间戳
504
-
505
- Returns:
506
- YYYY-MM-DD 格式的日期字符串
507
- """
508
- timestamp_s = timestamp_ms / 1000
509
- dt = datetime.fromtimestamp(timestamp_s)
510
- return dt.strftime('%Y-%m-%d')
511
-
512
- @staticmethod
513
- def get_start_timestamps(date_str: str) -> int:
514
- """
515
- 获取指定日期的开始毫秒时间戳(00:00:00.000)
516
-
517
- Args:
518
- date_str: 格式为"YYYY-MM-DD"的日期字符串
519
-
520
- Returns:
521
- 开始毫秒时间戳
522
- """
523
- start_of_day = datetime.strptime(date_str, "%Y-%m-%d")
524
- return int(start_of_day.timestamp() * 1000)
525
-
526
- @staticmethod
527
- def get_end_timestamps(date_str: str) -> int:
528
- """
529
- 获取指定日期的结束毫秒时间戳(23:59:59.999)
530
-
531
- Args:
532
- date_str: 格式为"YYYY-MM-DD"的日期字符串
533
-
534
- Returns:
535
- 结束毫秒时间戳
536
- """
537
- start_of_day = datetime.strptime(date_str, "%Y-%m-%d")
538
- end_of_day = start_of_day + timedelta(days=1) - timedelta(milliseconds=1)
539
- return int(end_of_day.timestamp() * 1000)
540
-
541
- # ==================== 日期格式转换 ====================
542
-
543
- @staticmethod
544
- def convert_datetime_to_date(datetime_str: str) -> str:
545
- """
546
- 将格式为 'YYYY-MM-DD HH:MM:SS' 的时间字符串转换为 'YYYY-MM-DD' 格式的日期字符串
547
-
548
- Args:
549
- datetime_str: 时间字符串,格式为 'YYYY-MM-DD HH:MM:SS'
550
-
551
- Returns:
552
- 日期字符串,格式为 'YYYY-MM-DD'
553
-
554
- Example:
555
- >>> convert_datetime_to_date("2025-06-27 09:49:16")
556
- '2025-06-27'
557
- """
558
- try:
559
- dt_obj = datetime.strptime(datetime_str, '%Y-%m-%d %H:%M:%S')
560
- return dt_obj.strftime('%Y-%m-%d')
561
- except ValueError:
562
- print(f"输入的时间字符串格式错误,需要 'YYYY-MM-DD HH:MM:SS' 格式,但得到: {datetime_str}")
563
- return datetime_str
564
-
565
- @staticmethod
566
- def date_trans(d_t: str) -> str:
567
- """
568
- 无斜杠日期转成有斜杠日期
569
-
570
- Args:
571
- d_t: 格式为 YYYY-MM-DD 的日期字符串
572
-
573
- Returns:
574
- 格式为 YYYYMMDD 的日期字符串
575
- """
576
- return datetime.strptime(d_t, "%Y-%m-%d").strftime("%Y%m%d")
577
-
578
- @staticmethod
579
- def format_date_cross_platform(date_str: str) -> str:
580
- """
581
- 跨平台格式化日期
582
-
583
- Args:
584
- date_str: 格式为 YYYY-MM-DD 的日期字符串
585
-
586
- Returns:
587
- 格式化后的日期字符串
588
- """
589
- date_obj = datetime.strptime(date_str, "%Y-%m-%d")
590
- import platform
591
- if platform.system() == "Windows":
592
- return date_obj.strftime("%Y/%#m/%#d")
593
- else: # Linux, macOS等
594
- return date_obj.strftime("%Y/%-m/%-d")
595
-
596
- # ==================== 日期比较和判断 ====================
597
-
598
- @staticmethod
599
- def is_date_greater_or_equal(date_str: str) -> bool:
600
- """
601
- 比较指定日期是否大于或等于今天的日期
602
-
603
- Args:
604
- date_str: 格式为YYYY-MM-DD的日期字符串
605
-
606
- Returns:
607
- 如果指定日期大于或等于今天返回True,否则返回False
608
- """
609
- try:
610
- year, month, day = map(int, date_str.split('-'))
611
- input_date = date(year, month, day)
612
- today = date.today()
613
- return input_date >= today
614
- except ValueError:
615
- print("日期格式不正确,请使用YYYY-MM-DD格式")
616
- return False
617
-
618
- @staticmethod
619
- def is_yesterday(create_time_str: str, dt: Optional[str] = None) -> bool:
620
- """
621
- 判断给定的时间字符串是否是昨天
622
-
623
- Args:
624
- create_time_str: 创建时间字符串,格式为 "%Y-%m-%d %H:%M:%S"
625
- dt: 日期字符串,格式为 "%Y-%m-%d" 表示某一天,默认为今天
626
-
627
- Returns:
628
- 如果 create_time_str 是昨天的日期,返回 True,否则返回 False
629
- """
630
- try:
631
- create_time = datetime.strptime(create_time_str, "%Y-%m-%d %H:%M:%S")
632
- if dt is None:
633
- dt = datetime.now()
634
- else:
635
- dt = datetime.strptime(dt, "%Y%m%d")
636
- except ValueError:
637
- raise ValueError("时间字符串格式不正确,请使用正确的格式:'%Y-%m-%d %H:%M:%S' 和 '%Y-%m-%d'")
638
-
639
- yesterday = dt - timedelta(days=1)
640
- return create_time.date() == yesterday.date()
641
-
642
- @staticmethod
643
- def is_yesterday_date(date_str: str) -> bool:
644
- """
645
- 判断给定的日期字符串是否是昨天
646
-
647
- Args:
648
- date_str: 日期字符串,格式为 "%Y-%m-%d"
649
-
650
- Returns:
651
- 如果 date_str 是昨天的日期,返回 True,否则返回 False
652
- """
653
- try:
654
- create_time = datetime.strptime(date_str, "%Y-%m-%d")
655
- dt = datetime.now()
656
- except ValueError:
657
- raise ValueError("时间字符串格式不正确,请使用正确的格式:'%Y-%m-%d'")
658
-
659
- yesterday = dt - timedelta(days=1)
660
- return create_time.date() == yesterday.date()
661
-
662
- # ==================== 文件时间相关 ====================
663
-
664
- @staticmethod
665
- def get_file_mtime(file_path: str, to_str: bool = True, tz_offset: int = 8) -> Union[str, datetime]:
666
- """
667
- 获取文件的修改时间
668
-
669
- Args:
670
- file_path: 文件路径
671
- to_str: 是否返回格式化字符串(默认 True)
672
- tz_offset: 时区偏移(默认东八区 +8)
673
-
674
- Returns:
675
- 格式化时间字符串或 datetime 对象
676
-
677
- Raises:
678
- FileNotFoundError: 当文件不存在时
679
- """
680
- if not os.path.exists(file_path):
681
- raise FileNotFoundError(f"文件不存在: {file_path}")
682
-
683
- mtime = os.path.getmtime(file_path)
684
- tz = timezone(timedelta(hours=tz_offset))
685
- mtime_dt = datetime.fromtimestamp(mtime, tz=tz)
686
-
687
- return mtime_dt.strftime('%Y-%m-%d %H:%M:%S') if to_str else mtime_dt
688
-
689
- # ==================== 便捷函数 ====================
690
- # 为了保持向后兼容,提供一些便捷函数
691
-
692
- def get_current_date() -> str:
693
- """获取当前日期,格式为 YYYYMMDD"""
694
- return TimeUtils.get_current_date()
695
-
696
- def get_current_datetime() -> str:
697
- """获取当前日期时间,格式为 YYYYMMDDHHMMSS"""
698
- return TimeUtils.get_current_datetime()
699
-
700
- def current_datetime() -> str:
701
- """获取当前日期时间,格式为 YYYY-MM-DD HH:MM:SS"""
702
- return TimeUtils.current_datetime()
703
-
704
- def today_date() -> str:
705
- """获取今天的日期,格式为 YYYY-MM-DD"""
706
- return TimeUtils.today_date()
707
-
708
- def today_date_hour() -> str:
709
- """获取今天的日期和小时,格式为 YYYY-MM-DD_HH"""
710
- return TimeUtils.today_date_hour()
711
-
712
- def get_yesterday(dt: Optional[str] = None) -> str:
713
- """获取昨天的日期"""
714
- return TimeUtils.get_yesterday(dt)
715
-
716
- def tomorrow_date() -> str:
717
- """获取明天的日期"""
718
- return TimeUtils.tomorrow_date()
719
-
720
- def before_yesterday() -> str:
721
- """获取前天的日期"""
722
- return TimeUtils.before_yesterday()
723
-
724
- def get_current_year() -> int:
725
- """获取当前年份"""
726
- return TimeUtils.get_current_year()
727
-
728
- def get_current_month() -> int:
729
- """获取当前月份"""
730
- return TimeUtils.get_current_month()
731
-
732
- def get_last_month() -> int:
733
- """获取上个月的月份"""
734
- return TimeUtils.get_last_month()
735
-
736
- def get_week_num() -> int:
737
- """获取当前是第几周"""
738
- return TimeUtils.get_week_num()
739
-
740
- def get_period() -> str:
741
- """获取当前时间段(上午/下午/晚上)"""
742
- return TimeUtils.get_period()
743
-
744
- def get_period2() -> str:
745
- """获取当前时间段(AM/PM)"""
746
- return TimeUtils.get_period2()
747
-
748
- def get_chinese_weekday(date_str: str) -> str:
749
- """根据输入的日期字符串返回中文星期几"""
750
- return TimeUtils.get_chinese_weekday(date_str)
751
-
752
- def get_weekday_name(date_str: str) -> str:
753
- """获取中文星期名称(简短格式)"""
754
- return TimeUtils.get_weekday_name(date_str)
755
-
756
- def is_in_month(time_str: str, month: int, fmt: str = "%Y-%m-%d") -> bool:
757
- """判断时间字符串是否在指定月份"""
758
- return TimeUtils.is_in_month(time_str, month, fmt)
759
-
760
- def date_trans(d_t: str) -> str:
761
- """无斜杠日期转成有斜杠日期"""
762
- return TimeUtils.date_trans(d_t)
763
-
764
- def is_date_greater_or_equal(date_str: str) -> bool:
765
- """比较指定日期是否大于或等于今天的日期"""
766
- return TimeUtils.is_date_greater_or_equal(date_str)
767
-
768
- def is_yesterday(create_time_str: str, dt: Optional[str] = None) -> bool:
769
- """判断给定的时间字符串是否是昨天"""
770
- return TimeUtils.is_yesterday(create_time_str, dt)
771
-
772
- def is_yesterday_date(date_str: str) -> bool:
773
- """判断给定的日期字符串是否是昨天"""
774
- return TimeUtils.is_yesterday_date(date_str)
775
-
776
- def get_file_mtime(file_path: str, to_str: bool = True, tz_offset: int = 8) -> Union[str, datetime]:
777
- """获取文件的修改时间"""
778
- return TimeUtils.get_file_mtime(file_path, to_str, tz_offset)
779
-
780
- def convert_timestamp_to_str(timestamp_ms: Optional[int]) -> str:
781
- """将毫秒时间戳转换为字符串"""
782
- return TimeUtils.convert_timestamp_to_str(timestamp_ms)
783
-
784
- def convert_timestamp_to_date(timestamp_ms: Union[int, float]) -> str:
785
- """将毫秒时间戳转换为日期字符串"""
786
- return TimeUtils.convert_timestamp_to_date(timestamp_ms)
787
-
788
- def convert_datetime_to_date(datetime_str: str) -> str:
789
- """将格式为 'YYYY-MM-DD HH:MM:SS' 的时间字符串转换为 'YYYY-MM-DD' 格式的日期字符串"""
790
- return TimeUtils.convert_datetime_to_date(datetime_str)
791
-
792
- def get_current_year_range() -> Tuple[str, str]:
793
- """获取当前年份的开始和结束日期"""
794
- return TimeUtils.get_current_year_range()
795
-
796
- def get_start_timestamps(date_str: str) -> int:
797
- """获取指定日期的开始毫秒时间戳(00:00:00.000)"""
798
- return TimeUtils.get_start_timestamps(date_str)
799
-
800
- def get_end_timestamps(date_str: str) -> int:
801
- """获取指定日期的结束毫秒时间戳(23:59:59.999)"""
802
- return TimeUtils.get_end_timestamps(date_str)
803
-
804
- def format_date_cross_platform(date_str: str) -> str:
805
- """跨平台格式化日期"""
806
- return TimeUtils.format_date_cross_platform(date_str)
807
-
808
- def get_past_7_days_range(start_from: Optional[str] = None) -> Tuple[str, str]:
809
- """获取过去7天的日期范围(包括结束日,共7天)"""
810
- return TimeUtils.get_past_7_days_range(start_from)
811
-
812
- def get_past_7_days_range_format(start_from: Optional[str] = None, format_str: str = '%Y-%m-%d') -> Tuple[str, str]:
813
- """获取过去7天的日期范围(包括结束日,共7天),支持自定义格式"""
814
- return TimeUtils.get_past_7_days_range_format(start_from, format_str)
815
-
816
- def get_past_nth_day(n: int, start_from: Optional[str] = None) -> str:
817
- """获取过去第n天的日期"""
818
- return TimeUtils.get_past_nth_day(n, start_from)
819
-
820
- def get_past_n_days_list(n: int, start_from: Optional[str] = None) -> List[str]:
821
- """获取过去n天的日期列表,从最旧到最近的日期"""
822
- return TimeUtils.get_past_n_days_list(n, start_from)
823
-
824
- def get_past_7_days_list(start_from: Optional[str] = None) -> List[str]:
825
- """获取过去7天的日期列表(不包含 start_from 当天),共7天"""
826
- return TimeUtils.get_past_7_days_list(start_from)
827
-
828
- def date_range(start_date: str, end_date: str) -> List[str]:
829
- """生成两个日期之间的日期列表"""
830
- return TimeUtils.date_range(start_date, end_date)
831
-
832
- def get_dates_from_first_of_month_to_yesterday() -> List[str]:
833
- """获取从本月第一天到昨天的日期列表"""
834
- return TimeUtils.get_dates_from_first_of_month_to_yesterday()
835
-
836
- def get_last_month_range() -> Tuple[str, str]:
837
- """获取上个月的第一天和最后一天"""
838
- return TimeUtils.get_last_month_range()
839
-
840
- def get_last_month_range_time_str() -> Tuple[str, str]:
841
- """获取上个月第一天和最后一天的时间字符串"""
842
- return TimeUtils.get_last_month_range_time_str()
843
-
844
- def get_last_month_range_time() -> Tuple[int, int]:
845
- """获取上个月第一天和最后一天的毫秒级时间戳"""
846
- return TimeUtils.get_last_month_range_time()
847
-
848
- # 为了向后兼容,保留一些旧函数名
849
- def get_past_7_days_range_old() -> Tuple[str, str]:
850
- """获取过去7天的日期范围(旧版本)"""
851
- end_date = datetime.today() - timedelta(days=1) # 昨天为结束日期
852
- start_date = end_date - timedelta(days=6) # 往前推6天为开始日期
853
- return start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d')
854
-
855
- def get_past_7_days_list_old() -> List[str]:
856
- """获取过去7天的日期列表(旧版本)"""
857
- today = datetime.today()
858
- return [
859
- (today - timedelta(days=i)).strftime('%Y-%m-%d')
860
- for i in range(1, 8)
861
- ]
862
-
863
- if __name__ == "__main__":
864
- # 测试示例
865
- print(f"当前日期: {today_date()}")
866
- print(f"昨天: {get_yesterday()}")
867
- print(f"明天: {tomorrow_date()}")
868
- print(f"当前年份: {get_current_year()}")
869
- print(f"当前月份: {get_current_month()}")
870
- print(f"当前周数: {get_week_num()}")
871
- print(f"当前时间段: {get_period()}")
872
- print(f"中文星期: {get_chinese_weekday(today_date())}")
873
-
874
- # 测试日期范围
875
- start, end = get_past_7_days_range()
876
- print(f"过去7天范围: {start} 到 {end}")
877
-
878
- # 测试时间戳转换
879
- current_ts = int(datetime.now().timestamp() * 1000)
880
- print(f"当前时间戳: {current_ts}")
881
- print(f"时间戳转字符串: {convert_timestamp_to_str(current_ts)}")
882
- print(f"时间戳转日期: {convert_timestamp_to_date(current_ts)}")
1
+ """
2
+ 时间工具模块
3
+ 提供各种时间相关的工具函数,包括日期获取、格式化、转换、计算等功能
4
+ """
5
+
6
+ import os
7
+ import calendar
8
+ from datetime import date, datetime, timedelta, timezone
9
+ from typing import Optional, Tuple, List, Union
10
+
11
+ class TimeUtils:
12
+ """时间工具类,提供各种时间相关的静态方法"""
13
+
14
+ # ==================== 当前时间获取 ====================
15
+
16
+ @staticmethod
17
+ def get_current_date() -> str:
18
+ """获取当前日期,格式为 YYYYMMDD"""
19
+ return datetime.now().strftime('%Y%m%d')
20
+
21
+ @staticmethod
22
+ def get_current_datetime() -> str:
23
+ """获取当前日期时间,格式为 YYYYMMDDHHMMSS"""
24
+ return datetime.now().strftime('%Y%m%d%H%M%S')
25
+
26
+ @staticmethod
27
+ def current_datetime() -> str:
28
+ """获取当前日期时间,格式为 YYYY-MM-DD HH:MM:SS"""
29
+ return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
30
+
31
+ @staticmethod
32
+ def today_date() -> str:
33
+ """获取今天的日期,格式为 YYYY-MM-DD"""
34
+ return datetime.now().strftime('%Y-%m-%d')
35
+
36
+ @staticmethod
37
+ def today_date_hour() -> str:
38
+ """获取今天的日期和小时,格式为 YYYY-MM-DD_HH"""
39
+ return datetime.now().strftime('%Y-%m-%d_%H')
40
+
41
+ @staticmethod
42
+ def get_current_year() -> int:
43
+ """获取当前年份"""
44
+ return datetime.now().year
45
+
46
+ @staticmethod
47
+ def get_current_month() -> int:
48
+ """获取当前月份(1-12)"""
49
+ return datetime.now().month
50
+
51
+ @staticmethod
52
+ def get_current_year_range() -> Tuple[str, str]:
53
+ """获取当前年份的开始和结束日期"""
54
+ current_year = datetime.now().year
55
+ start_date = datetime(current_year, 1, 1).strftime('%Y-%m-%d')
56
+ end_date = datetime(current_year, 12, 31).strftime('%Y-%m-%d')
57
+ return start_date, end_date
58
+
59
+ # ==================== 相对日期获取 ====================
60
+
61
+ @staticmethod
62
+ def get_yesterday(dt: Optional[str] = None) -> str:
63
+ """
64
+ 获取昨天的日期
65
+
66
+ Args:
67
+ dt: 可选的基础日期,格式为 YYYYMMDD,默认为今天
68
+
69
+ Returns:
70
+ 昨天的日期,格式为 YYYY-MM-DD
71
+ """
72
+ if dt is None:
73
+ dt = datetime.now()
74
+ else:
75
+ dt = datetime.strptime(dt, "%Y%m%d")
76
+ yesterday = dt - timedelta(days=1)
77
+ return yesterday.strftime("%Y-%m-%d")
78
+
79
+ @staticmethod
80
+ def before_yesterday() -> str:
81
+ """获取前天的日期"""
82
+ return (datetime.now().date() - timedelta(days=2)).strftime("%Y-%m-%d")
83
+
84
+ @staticmethod
85
+ def tomorrow_date() -> str:
86
+ """获取明天的日期"""
87
+ return (datetime.now().date() + timedelta(days=1)).strftime("%Y-%m-%d")
88
+
89
+ @staticmethod
90
+ def get_last_month() -> int:
91
+ """获取上个月的月份"""
92
+ today = datetime.today()
93
+ last_month = today.month - 1 if today.month > 1 else 12
94
+ return last_month
95
+
96
+ @staticmethod
97
+ def get_last_two_month() -> int:
98
+ """获取上上个月的月份"""
99
+ today = datetime.today()
100
+ # 计算上上个月:当前月份减2
101
+ last_two_month = today.month - 2
102
+ # 处理跨年情况
103
+ if last_two_month < 1:
104
+ last_two_month += 12
105
+ return last_two_month
106
+
107
+ # ==================== 日期范围计算 ====================
108
+
109
+ @staticmethod
110
+ def get_past_7_days_range(start_from: Optional[str] = None, format_str: str = '%Y-%m-%d') -> Tuple[str, str,]:
111
+ """
112
+ 获取过去7天的日期范围(包括结束日,共7天)
113
+
114
+ Args:
115
+ start_from: 可选的起始参考日期(格式 'YYYY-MM-DD'),默认以今天为起点
116
+
117
+ Returns:
118
+ (start_date_str, end_date_str) 日期范围元组
119
+
120
+ Example:
121
+ >>> get_past_7_days_range('2025-07-02')
122
+ ('2025-06-25', '2025-07-01')
123
+ """
124
+ if start_from:
125
+ try:
126
+ base_date = datetime.strptime(start_from, '%Y-%m-%d')
127
+ except ValueError:
128
+ raise ValueError("start_from 格式必须是 'YYYY-MM-DD'")
129
+ else:
130
+ base_date = datetime.today()
131
+
132
+ end_date = base_date - timedelta(days=1) # 默认昨天为结束
133
+ start_date = end_date - timedelta(days=6) # 往前推6天为开始
134
+
135
+ return start_date.strftime(format_str), end_date.strftime(format_str)
136
+
137
+ @staticmethod
138
+ def get_past_7_days_range_format(start_from: Optional[str] = None, format_str: str = '%Y-%m-%d') -> Tuple[str, str]:
139
+ """
140
+ 获取过去7天的日期范围(包括结束日,共7天),支持自定义格式
141
+
142
+ Args:
143
+ start_from: 可选的起始参考日期(格式 'YYYY-MM-DD'),默认以今天为起点
144
+ format_str: 日期格式字符串
145
+
146
+ Returns:
147
+ (start_date_str, end_date_str) 日期范围元组
148
+ """
149
+ if start_from:
150
+ try:
151
+ base_date = datetime.strptime(start_from, '%Y-%m-%d')
152
+ except ValueError:
153
+ raise ValueError("start_from 格式必须是 'YYYY-MM-DD'")
154
+ else:
155
+ base_date = datetime.today()
156
+
157
+ end_date = base_date - timedelta(days=1) # 默认昨天为结束
158
+ start_date = end_date - timedelta(days=6) # 往前推6天为开始
159
+
160
+ return start_date.strftime(format_str), end_date.strftime(format_str)
161
+
162
+ @staticmethod
163
+ def get_month_first_day(start_from: Optional[str] = None, format_str: str = '%Y-%m-%d') -> str:
164
+ """
165
+ 获取某月的第一天
166
+
167
+ Args:
168
+ start_from: 参考日期,格式为'YYYY-MM-DD',默认使用今天
169
+ format_str: 返回的日期格式,默认是'%Y-%m-%d'
170
+
171
+ Returns:
172
+ 指定格式的某月第一天日期字符串
173
+
174
+ Example:
175
+ >>> get_month_first_day('2025-07-02')
176
+ '2025-07-01'
177
+ """
178
+ if start_from:
179
+ try:
180
+ base_date = datetime.strptime(start_from, '%Y-%m-%d')
181
+ except ValueError:
182
+ raise ValueError("start_from 格式必须是 'YYYY-MM-DD'")
183
+ else:
184
+ base_date = datetime.today()
185
+
186
+ # 获取当月第一天
187
+ first_day = base_date.replace(day=1)
188
+ return first_day.strftime(format_str)
189
+
190
+ @staticmethod
191
+ def get_past_nth_day(n: int, start_from: Optional[str] = None, format_str: str = '%Y-%m-%d') -> str:
192
+ """
193
+ 获取过去第n天的日期
194
+
195
+ Args:
196
+ n: 获取过去第n天的日期(n=1 表示昨天,n=2 表示前天,以此类推)
197
+ start_from: 可选的起始参考日期(格式 'YYYY-MM-DD'),默认以今天为起点
198
+
199
+ Returns:
200
+ 'YYYY-MM-DD' 格式的日期
201
+
202
+ Example:
203
+ >>> get_past_nth_day(29, '2025-07-02')
204
+ '2025-06-03'
205
+ """
206
+ if start_from:
207
+ try:
208
+ base_date = datetime.strptime(start_from, '%Y-%m-%d')
209
+ except ValueError:
210
+ raise ValueError("start_from 格式必须是 'YYYY-MM-DD'")
211
+ else:
212
+ base_date = datetime.today()
213
+
214
+ past_date = base_date - timedelta(days=n)
215
+ return past_date.strftime(format_str)
216
+
217
+ @staticmethod
218
+ def get_past_n_days_list(n: int, start_from: Optional[str] = None) -> List[str]:
219
+ """
220
+ 获取过去n天的日期列表,从最旧到最近的日期
221
+
222
+ Args:
223
+ n: 获取过去多少天
224
+ start_from: 可选的起始参考日期(格式 'YYYY-MM-DD'),默认以今天为起点
225
+
226
+ Returns:
227
+ ['YYYY-MM-DD', ..., 'YYYY-MM-DD'],从旧到新排序
228
+
229
+ Example:
230
+ >>> get_past_n_days_list(7, '2025-07-02')
231
+ ['2025-07-01', '2025-06-30', '2025-06-29', '2025-06-28', '2025-06-27', '2025-06-26', '2025-06-25']
232
+ """
233
+ if start_from:
234
+ try:
235
+ base_date = datetime.strptime(start_from, '%Y-%m-%d')
236
+ except ValueError:
237
+ raise ValueError("start_from 格式必须是 'YYYY-MM-DD'")
238
+ else:
239
+ base_date = datetime.today()
240
+
241
+ return [
242
+ (base_date - timedelta(days=i)).strftime('%Y-%m-%d')
243
+ for i in range(1, n + 1)
244
+ ]
245
+
246
+ @staticmethod
247
+ def get_past_7_days_list(start_from: Optional[str] = None) -> List[str]:
248
+ """
249
+ 获取过去7天的日期列表(不包含 start_from 当天),共7天
250
+
251
+ Args:
252
+ start_from: 可选的起始参考日期(格式 'YYYY-MM-DD'),默认以今天为起点
253
+
254
+ Returns:
255
+ ['YYYY-MM-DD', ..., 'YYYY-MM-DD'],从旧到新排序
256
+ """
257
+ if start_from:
258
+ try:
259
+ base_date = datetime.strptime(start_from, '%Y-%m-%d')
260
+ except ValueError:
261
+ raise ValueError("start_from 格式必须是 'YYYY-MM-DD'")
262
+ else:
263
+ base_date = datetime.today()
264
+
265
+ return [
266
+ (base_date - timedelta(days=i)).strftime('%Y-%m-%d')
267
+ for i in range(1, 8)
268
+ ]
269
+
270
+ @staticmethod
271
+ def date_range(start_date: str, end_date: str) -> List[str]:
272
+ """
273
+ 生成两个日期之间的日期列表
274
+
275
+ Args:
276
+ start_date: 开始日期,格式为YYYY-MM-DD
277
+ end_date: 结束日期,格式为YYYY-MM-DD
278
+
279
+ Returns:
280
+ 包含两个日期之间所有日期的列表,日期格式为YYYY-MM-DD
281
+
282
+ Raises:
283
+ ValueError: 当开始日期大于结束日期时
284
+ """
285
+ start = datetime.strptime(start_date, "%Y-%m-%d")
286
+ end = datetime.strptime(end_date, "%Y-%m-%d")
287
+
288
+ if start > end:
289
+ raise ValueError("开始日期不能大于结束日期")
290
+
291
+ date_list = []
292
+ current_date = start
293
+ while current_date <= end:
294
+ date_list.append(current_date.strftime("%Y-%m-%d"))
295
+ current_date += timedelta(days=1)
296
+
297
+ return date_list
298
+
299
+ @staticmethod
300
+ def get_dates_from_first_of_month_to_yesterday() -> List[str]:
301
+ """获取从本月第一天到昨天的日期列表
302
+ 如果今天是本月第一天,则返回上个月的日期列表
303
+ """
304
+ today = datetime.today()
305
+ yesterday = today - timedelta(days=1)
306
+
307
+ # 如果今天是本月第一天,取上个月
308
+ if today.day == 1:
309
+ # 找到上个月最后一天
310
+ last_month_last_day = today - timedelta(days=1)
311
+ # 上个月第一天
312
+ first_day_of_last_month = last_month_last_day.replace(day=1)
313
+ start_date = first_day_of_last_month
314
+ end_date = last_month_last_day
315
+ else:
316
+ start_date = today.replace(day=1)
317
+ end_date = yesterday
318
+
319
+ date_list = []
320
+ current_date = start_date
321
+ while current_date <= end_date:
322
+ date_list.append(current_date.strftime('%Y-%m-%d'))
323
+ current_date += timedelta(days=1)
324
+
325
+ return date_list
326
+
327
+ # ==================== 月份相关 ====================
328
+
329
+ @staticmethod
330
+ def get_last_month_range() -> Tuple[str, str]:
331
+ """获取上个月的第一天和最后一天"""
332
+ today = datetime.today()
333
+ last_month = today.month - 1 if today.month > 1 else 12
334
+ year = today.year if today.month > 1 else today.year - 1
335
+
336
+ first_day = datetime(year, last_month, 1)
337
+ last_day = datetime(year, last_month, calendar.monthrange(year, last_month)[1])
338
+
339
+ return first_day.strftime("%Y-%m-%d"), last_day.strftime("%Y-%m-%d")
340
+
341
+ @staticmethod
342
+ def get_last_two_month_range() -> Tuple[str, str]:
343
+ """获取上上个月的第一天和最后一天"""
344
+ today = datetime.today()
345
+ # 计算上上个月
346
+ last_two_month = today.month - 2
347
+ year = today.year
348
+
349
+ # 处理跨年情况
350
+ if last_two_month < 1:
351
+ last_two_month += 12
352
+ year -= 1
353
+
354
+ first_day = datetime(year, last_two_month, 1)
355
+ last_day = datetime(year, last_two_month, calendar.monthrange(year, last_two_month)[1])
356
+
357
+ return first_day.strftime("%Y-%m-%d"), last_day.strftime("%Y-%m-%d")
358
+
359
+ @staticmethod
360
+ def get_last_month_range_time_str() -> Tuple[str, str]:
361
+ """获取上个月第一天和最后一天的时间字符串"""
362
+ today = datetime.today()
363
+ last_month = today.month - 1 if today.month > 1 else 12
364
+ year = today.year if today.month > 1 else today.year - 1
365
+
366
+ first_day = datetime(year, last_month, 1, 0, 0, 0)
367
+ last_day = datetime(year, last_month, calendar.monthrange(year, last_month)[1], 23, 59, 59)
368
+
369
+ start_time_str = first_day.strftime("%Y-%m-%d %H:%M:%S")
370
+ end_time_str = last_day.strftime("%Y-%m-%d %H:%M:%S")
371
+
372
+ return start_time_str, end_time_str
373
+
374
+ @staticmethod
375
+ def get_last_month_range_time() -> Tuple[int, int]:
376
+ """获取上个月第一天和最后一天的毫秒级时间戳"""
377
+ today = datetime.today()
378
+ last_month = today.month - 1 if today.month > 1 else 12
379
+ year = today.year if today.month > 1 else today.year - 1
380
+
381
+ first_day = datetime(year, last_month, 1, 0, 0, 0)
382
+ last_day = datetime(year, last_month, calendar.monthrange(year, last_month)[1], 23, 59, 59, 0)
383
+
384
+ start_timestamp = int(first_day.timestamp() * 1000)
385
+ end_timestamp = int(last_day.timestamp() * 1000)
386
+
387
+ return start_timestamp, end_timestamp
388
+
389
+ @staticmethod
390
+ def get_year_range_time(year=2024):
391
+ """获取某一整年的第一天和最后一天的毫秒级时间戳"""
392
+ first_day = datetime(year, 1, 1, 0, 0, 0)
393
+ last_day = datetime(year, 12, 31, 0, 0, 0, 0)
394
+
395
+ start_timestamp = int(first_day.timestamp() * 1000)
396
+ end_timestamp = int(last_day.timestamp() * 1000)
397
+
398
+ return start_timestamp, end_timestamp
399
+
400
+ @staticmethod
401
+ def is_in_month(time_str: str, month: int, fmt: str = "%Y-%m-%d") -> bool:
402
+ """
403
+ 判断时间字符串是否在指定月份
404
+
405
+ Args:
406
+ time_str: 时间字符串
407
+ month: 月份(1-12)
408
+ fmt: 时间格式
409
+
410
+ Returns:
411
+ 如果时间在指定月份返回True,否则返回False
412
+ """
413
+ try:
414
+ dt = datetime.strptime(time_str, fmt)
415
+ return dt.month == month
416
+ except ValueError:
417
+ return False
418
+
419
+ # ==================== 星期相关 ====================
420
+
421
+ @staticmethod
422
+ def get_week_num() -> int:
423
+ """获取当前是第几周"""
424
+ today = date.today()
425
+ week_num = today.isocalendar()[1] # 返回 (year, week_num, weekday)
426
+ return week_num
427
+
428
+ @staticmethod
429
+ def get_chinese_weekday(date_str: str) -> str:
430
+ """
431
+ 根据输入的日期字符串返回中文星期几
432
+
433
+ Args:
434
+ date_str: 格式为'YYYY-MM-DD'的日期字符串
435
+
436
+ Returns:
437
+ 中文星期几,如'星期一'
438
+
439
+ Example:
440
+ >>> get_chinese_weekday('2025-04-15')
441
+ '星期二'
442
+ """
443
+ try:
444
+ date_obj = datetime.strptime(date_str, '%Y-%m-%d')
445
+ weekday_num = date_obj.weekday()
446
+ weekday_cn = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
447
+ return weekday_cn[weekday_num]
448
+ except ValueError as e:
449
+ raise ValueError(f"日期格式错误,请输入'YYYY-MM-DD'格式的日期字符串。错误详情: {str(e)}")
450
+
451
+ @staticmethod
452
+ def get_weekday_name(date_str: str) -> str:
453
+ """获取中文星期名称(简短格式)"""
454
+ weekdays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
455
+ date_obj = datetime.strptime(date_str, '%Y-%m-%d')
456
+ return weekdays[date_obj.weekday()]
457
+
458
+ # ==================== 时间段相关 ====================
459
+
460
+ @staticmethod
461
+ def get_period() -> str:
462
+ """获取当前时间段(上午/下午/晚上)"""
463
+ hour = datetime.now().hour
464
+ if 5 <= hour < 12:
465
+ return "上午"
466
+ elif 12 <= hour < 18:
467
+ return "下午"
468
+ else:
469
+ return "晚上"
470
+
471
+ @staticmethod
472
+ def get_period2() -> str:
473
+ """获取当前时间段(AM/PM)"""
474
+ now = datetime.now()
475
+ period = now.strftime("%p") # 返回AM或者PM
476
+ return period
477
+
478
+ # ==================== 时间戳转换 ====================
479
+
480
+ @staticmethod
481
+ def convert_timestamp_to_str(timestamp_ms: Optional[int]) -> str:
482
+ """
483
+ 将毫秒时间戳转换为字符串
484
+
485
+ Args:
486
+ timestamp_ms: 毫秒时间戳
487
+
488
+ Returns:
489
+ 格式化的时间字符串,如果输入为None则返回'-'
490
+ """
491
+ if timestamp_ms is None:
492
+ return '-'
493
+ timestamp_s = int(timestamp_ms) / 1000
494
+ dt = datetime.fromtimestamp(timestamp_s)
495
+ return dt.strftime('%Y-%m-%d %H:%M:%S')
496
+
497
+ @staticmethod
498
+ def convert_timestamp_to_date(timestamp_ms: Union[int, float]) -> str:
499
+ """
500
+ 将毫秒时间戳转换为日期字符串
501
+
502
+ Args:
503
+ timestamp_ms: 毫秒时间戳
504
+
505
+ Returns:
506
+ YYYY-MM-DD 格式的日期字符串
507
+ """
508
+ timestamp_s = timestamp_ms / 1000
509
+ dt = datetime.fromtimestamp(timestamp_s)
510
+ return dt.strftime('%Y-%m-%d')
511
+
512
+ @staticmethod
513
+ def get_start_timestamps(date_str: str) -> int:
514
+ """
515
+ 获取指定日期的开始毫秒时间戳(00:00:00.000)
516
+
517
+ Args:
518
+ date_str: 格式为"YYYY-MM-DD"的日期字符串
519
+
520
+ Returns:
521
+ 开始毫秒时间戳
522
+ """
523
+ start_of_day = datetime.strptime(date_str, "%Y-%m-%d")
524
+ return int(start_of_day.timestamp() * 1000)
525
+
526
+ @staticmethod
527
+ def get_end_timestamps(date_str: str) -> int:
528
+ """
529
+ 获取指定日期的结束毫秒时间戳(23:59:59.999)
530
+
531
+ Args:
532
+ date_str: 格式为"YYYY-MM-DD"的日期字符串
533
+
534
+ Returns:
535
+ 结束毫秒时间戳
536
+ """
537
+ start_of_day = datetime.strptime(date_str, "%Y-%m-%d")
538
+ end_of_day = start_of_day + timedelta(days=1) - timedelta(milliseconds=1)
539
+ return int(end_of_day.timestamp() * 1000)
540
+
541
+ # ==================== 日期格式转换 ====================
542
+
543
+ @staticmethod
544
+ def convert_datetime_to_date(datetime_str: str) -> str:
545
+ """
546
+ 将格式为 'YYYY-MM-DD HH:MM:SS' 的时间字符串转换为 'YYYY-MM-DD' 格式的日期字符串
547
+
548
+ Args:
549
+ datetime_str: 时间字符串,格式为 'YYYY-MM-DD HH:MM:SS'
550
+
551
+ Returns:
552
+ 日期字符串,格式为 'YYYY-MM-DD'
553
+
554
+ Example:
555
+ >>> convert_datetime_to_date("2025-06-27 09:49:16")
556
+ '2025-06-27'
557
+ """
558
+ try:
559
+ dt_obj = datetime.strptime(datetime_str, '%Y-%m-%d %H:%M:%S')
560
+ return dt_obj.strftime('%Y-%m-%d')
561
+ except ValueError:
562
+ print(f"输入的时间字符串格式错误,需要 'YYYY-MM-DD HH:MM:SS' 格式,但得到: {datetime_str}")
563
+ return datetime_str
564
+
565
+ @staticmethod
566
+ def date_trans(d_t: str) -> str:
567
+ """
568
+ 无斜杠日期转成有斜杠日期
569
+
570
+ Args:
571
+ d_t: 格式为 YYYY-MM-DD 的日期字符串
572
+
573
+ Returns:
574
+ 格式为 YYYYMMDD 的日期字符串
575
+ """
576
+ return datetime.strptime(d_t, "%Y-%m-%d").strftime("%Y%m%d")
577
+
578
+ @staticmethod
579
+ def format_date_cross_platform(date_str: str) -> str:
580
+ """
581
+ 跨平台格式化日期
582
+
583
+ Args:
584
+ date_str: 格式为 YYYY-MM-DD 的日期字符串
585
+
586
+ Returns:
587
+ 格式化后的日期字符串
588
+ """
589
+ date_obj = datetime.strptime(date_str, "%Y-%m-%d")
590
+ import platform
591
+ if platform.system() == "Windows":
592
+ return date_obj.strftime("%Y/%#m/%#d")
593
+ else: # Linux, macOS等
594
+ return date_obj.strftime("%Y/%-m/%-d")
595
+
596
+ # ==================== 日期比较和判断 ====================
597
+
598
+ @staticmethod
599
+ def is_date_greater_or_equal(date_str: str) -> bool:
600
+ """
601
+ 比较指定日期是否大于或等于今天的日期
602
+
603
+ Args:
604
+ date_str: 格式为YYYY-MM-DD的日期字符串
605
+
606
+ Returns:
607
+ 如果指定日期大于或等于今天返回True,否则返回False
608
+ """
609
+ try:
610
+ year, month, day = map(int, date_str.split('-'))
611
+ input_date = date(year, month, day)
612
+ today = date.today()
613
+ return input_date >= today
614
+ except ValueError:
615
+ print("日期格式不正确,请使用YYYY-MM-DD格式")
616
+ return False
617
+
618
+ @staticmethod
619
+ def is_yesterday(create_time_str: str, dt: Optional[str] = None) -> bool:
620
+ """
621
+ 判断给定的时间字符串是否是昨天
622
+
623
+ Args:
624
+ create_time_str: 创建时间字符串,格式为 "%Y-%m-%d %H:%M:%S"
625
+ dt: 日期字符串,格式为 "%Y-%m-%d" 表示某一天,默认为今天
626
+
627
+ Returns:
628
+ 如果 create_time_str 是昨天的日期,返回 True,否则返回 False
629
+ """
630
+ try:
631
+ create_time = datetime.strptime(create_time_str, "%Y-%m-%d %H:%M:%S")
632
+ if dt is None:
633
+ dt = datetime.now()
634
+ else:
635
+ dt = datetime.strptime(dt, "%Y%m%d")
636
+ except ValueError:
637
+ raise ValueError("时间字符串格式不正确,请使用正确的格式:'%Y-%m-%d %H:%M:%S' 和 '%Y-%m-%d'")
638
+
639
+ yesterday = dt - timedelta(days=1)
640
+ return create_time.date() == yesterday.date()
641
+
642
+ @staticmethod
643
+ def is_yesterday_date(date_str: str, format="%Y-%m-%d") -> bool:
644
+ """
645
+ 判断给定的日期字符串是否是昨天
646
+
647
+ Args:
648
+ date_str: 日期字符串,格式为 "%Y-%m-%d"
649
+
650
+ Returns:
651
+ 如果 date_str 是昨天的日期,返回 True,否则返回 False
652
+ """
653
+ try:
654
+ create_time = datetime.strptime(date_str, format)
655
+ dt = datetime.now()
656
+ except ValueError:
657
+ raise ValueError("时间字符串格式不正确,请使用正确的格式:'%Y-%m-%d'")
658
+
659
+ yesterday = dt - timedelta(days=1)
660
+ return create_time.date() == yesterday.date()
661
+
662
+ # ==================== 文件时间相关 ====================
663
+
664
+ @staticmethod
665
+ def get_file_mtime(file_path: str, to_str: bool = True, tz_offset: int = 8) -> Union[str, datetime]:
666
+ """
667
+ 获取文件的修改时间
668
+
669
+ Args:
670
+ file_path: 文件路径
671
+ to_str: 是否返回格式化字符串(默认 True)
672
+ tz_offset: 时区偏移(默认东八区 +8)
673
+
674
+ Returns:
675
+ 格式化时间字符串或 datetime 对象
676
+
677
+ Raises:
678
+ FileNotFoundError: 当文件不存在时
679
+ """
680
+ if not os.path.exists(file_path):
681
+ raise FileNotFoundError(f"文件不存在: {file_path}")
682
+
683
+ mtime = os.path.getmtime(file_path)
684
+ tz = timezone(timedelta(hours=tz_offset))
685
+ mtime_dt = datetime.fromtimestamp(mtime, tz=tz)
686
+
687
+ return mtime_dt.strftime('%Y-%m-%d %H:%M:%S') if to_str else mtime_dt
688
+
689
+ # ==================== 便捷函数 ====================
690
+ # 为了保持向后兼容,提供一些便捷函数
691
+
692
+ def get_current_date() -> str:
693
+ """获取当前日期,格式为 YYYYMMDD"""
694
+ return TimeUtils.get_current_date()
695
+
696
+ def get_current_datetime() -> str:
697
+ """获取当前日期时间,格式为 YYYYMMDDHHMMSS"""
698
+ return TimeUtils.get_current_datetime()
699
+
700
+ def current_datetime() -> str:
701
+ """获取当前日期时间,格式为 YYYY-MM-DD HH:MM:SS"""
702
+ return TimeUtils.current_datetime()
703
+
704
+ def today_date() -> str:
705
+ """获取今天的日期,格式为 YYYY-MM-DD"""
706
+ return TimeUtils.today_date()
707
+
708
+ def today_date_hour() -> str:
709
+ """获取今天的日期和小时,格式为 YYYY-MM-DD_HH"""
710
+ return TimeUtils.today_date_hour()
711
+
712
+ def get_yesterday(dt: Optional[str] = None) -> str:
713
+ """获取昨天的日期"""
714
+ return TimeUtils.get_yesterday(dt)
715
+
716
+ def tomorrow_date() -> str:
717
+ """获取明天的日期"""
718
+ return TimeUtils.tomorrow_date()
719
+
720
+ def before_yesterday() -> str:
721
+ """获取前天的日期"""
722
+ return TimeUtils.before_yesterday()
723
+
724
+ def get_current_year() -> int:
725
+ """获取当前年份"""
726
+ return TimeUtils.get_current_year()
727
+
728
+ def get_current_month() -> int:
729
+ """获取当前月份"""
730
+ return TimeUtils.get_current_month()
731
+
732
+ def get_last_month() -> int:
733
+ """获取上个月的月份"""
734
+ return TimeUtils.get_last_month()
735
+
736
+ def get_week_num() -> int:
737
+ """获取当前是第几周"""
738
+ return TimeUtils.get_week_num()
739
+
740
+ def get_period() -> str:
741
+ """获取当前时间段(上午/下午/晚上)"""
742
+ return TimeUtils.get_period()
743
+
744
+ def get_period2() -> str:
745
+ """获取当前时间段(AM/PM)"""
746
+ return TimeUtils.get_period2()
747
+
748
+ def get_chinese_weekday(date_str: str) -> str:
749
+ """根据输入的日期字符串返回中文星期几"""
750
+ return TimeUtils.get_chinese_weekday(date_str)
751
+
752
+ def get_weekday_name(date_str: str) -> str:
753
+ """获取中文星期名称(简短格式)"""
754
+ return TimeUtils.get_weekday_name(date_str)
755
+
756
+ def is_in_month(time_str: str, month: int, fmt: str = "%Y-%m-%d") -> bool:
757
+ """判断时间字符串是否在指定月份"""
758
+ return TimeUtils.is_in_month(time_str, month, fmt)
759
+
760
+ def date_trans(d_t: str) -> str:
761
+ """无斜杠日期转成有斜杠日期"""
762
+ return TimeUtils.date_trans(d_t)
763
+
764
+ def is_date_greater_or_equal(date_str: str) -> bool:
765
+ """比较指定日期是否大于或等于今天的日期"""
766
+ return TimeUtils.is_date_greater_or_equal(date_str)
767
+
768
+ def is_yesterday(create_time_str: str, dt: Optional[str] = None) -> bool:
769
+ """判断给定的时间字符串是否是昨天"""
770
+ return TimeUtils.is_yesterday(create_time_str, dt)
771
+
772
+ def is_yesterday_date(date_str: str) -> bool:
773
+ """判断给定的日期字符串是否是昨天"""
774
+ return TimeUtils.is_yesterday_date(date_str)
775
+
776
+ def get_file_mtime(file_path: str, to_str: bool = True, tz_offset: int = 8) -> Union[str, datetime]:
777
+ """获取文件的修改时间"""
778
+ return TimeUtils.get_file_mtime(file_path, to_str, tz_offset)
779
+
780
+ def convert_timestamp_to_str(timestamp_ms: Optional[int]) -> str:
781
+ """将毫秒时间戳转换为字符串"""
782
+ return TimeUtils.convert_timestamp_to_str(timestamp_ms)
783
+
784
+ def convert_timestamp_to_date(timestamp_ms: Union[int, float]) -> str:
785
+ """将毫秒时间戳转换为日期字符串"""
786
+ return TimeUtils.convert_timestamp_to_date(timestamp_ms)
787
+
788
+ def convert_datetime_to_date(datetime_str: str) -> str:
789
+ """将格式为 'YYYY-MM-DD HH:MM:SS' 的时间字符串转换为 'YYYY-MM-DD' 格式的日期字符串"""
790
+ return TimeUtils.convert_datetime_to_date(datetime_str)
791
+
792
+ def get_current_year_range() -> Tuple[str, str]:
793
+ """获取当前年份的开始和结束日期"""
794
+ return TimeUtils.get_current_year_range()
795
+
796
+ def get_start_timestamps(date_str: str) -> int:
797
+ """获取指定日期的开始毫秒时间戳(00:00:00.000)"""
798
+ return TimeUtils.get_start_timestamps(date_str)
799
+
800
+ def get_end_timestamps(date_str: str) -> int:
801
+ """获取指定日期的结束毫秒时间戳(23:59:59.999)"""
802
+ return TimeUtils.get_end_timestamps(date_str)
803
+
804
+ def format_date_cross_platform(date_str: str) -> str:
805
+ """跨平台格式化日期"""
806
+ return TimeUtils.format_date_cross_platform(date_str)
807
+
808
+ def get_past_7_days_range(start_from: Optional[str] = None) -> Tuple[str, str]:
809
+ """获取过去7天的日期范围(包括结束日,共7天)"""
810
+ return TimeUtils.get_past_7_days_range(start_from)
811
+
812
+ def get_past_7_days_range_format(start_from: Optional[str] = None, format_str: str = '%Y-%m-%d') -> Tuple[str, str]:
813
+ """获取过去7天的日期范围(包括结束日,共7天),支持自定义格式"""
814
+ return TimeUtils.get_past_7_days_range_format(start_from, format_str)
815
+
816
+ def get_past_nth_day(n: int, start_from: Optional[str] = None) -> str:
817
+ """获取过去第n天的日期"""
818
+ return TimeUtils.get_past_nth_day(n, start_from)
819
+
820
+ def get_past_n_days_list(n: int, start_from: Optional[str] = None) -> List[str]:
821
+ """获取过去n天的日期列表,从最旧到最近的日期"""
822
+ return TimeUtils.get_past_n_days_list(n, start_from)
823
+
824
+ def get_past_7_days_list(start_from: Optional[str] = None) -> List[str]:
825
+ """获取过去7天的日期列表(不包含 start_from 当天),共7天"""
826
+ return TimeUtils.get_past_7_days_list(start_from)
827
+
828
+ def date_range(start_date: str, end_date: str) -> List[str]:
829
+ """生成两个日期之间的日期列表"""
830
+ return TimeUtils.date_range(start_date, end_date)
831
+
832
+ def get_dates_from_first_of_month_to_yesterday() -> List[str]:
833
+ """获取从本月第一天到昨天的日期列表"""
834
+ return TimeUtils.get_dates_from_first_of_month_to_yesterday()
835
+
836
+ def get_last_month_range() -> Tuple[str, str]:
837
+ """获取上个月的第一天和最后一天"""
838
+ return TimeUtils.get_last_month_range()
839
+
840
+ def get_last_month_range_time_str() -> Tuple[str, str]:
841
+ """获取上个月第一天和最后一天的时间字符串"""
842
+ return TimeUtils.get_last_month_range_time_str()
843
+
844
+ def get_last_month_range_time() -> Tuple[int, int]:
845
+ """获取上个月第一天和最后一天的毫秒级时间戳"""
846
+ return TimeUtils.get_last_month_range_time()
847
+
848
+ # 为了向后兼容,保留一些旧函数名
849
+ def get_past_7_days_range_old() -> Tuple[str, str]:
850
+ """获取过去7天的日期范围(旧版本)"""
851
+ end_date = datetime.today() - timedelta(days=1) # 昨天为结束日期
852
+ start_date = end_date - timedelta(days=6) # 往前推6天为开始日期
853
+ return start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d')
854
+
855
+ def get_past_7_days_list_old() -> List[str]:
856
+ """获取过去7天的日期列表(旧版本)"""
857
+ today = datetime.today()
858
+ return [
859
+ (today - timedelta(days=i)).strftime('%Y-%m-%d')
860
+ for i in range(1, 8)
861
+ ]
862
+
863
+ if __name__ == "__main__":
864
+ # 测试示例
865
+ print(f"当前日期: {today_date()}")
866
+ print(f"昨天: {get_yesterday()}")
867
+ print(f"明天: {tomorrow_date()}")
868
+ print(f"当前年份: {get_current_year()}")
869
+ print(f"当前月份: {get_current_month()}")
870
+ print(f"当前周数: {get_week_num()}")
871
+ print(f"当前时间段: {get_period()}")
872
+ print(f"中文星期: {get_chinese_weekday(today_date())}")
873
+
874
+ # 测试日期范围
875
+ start, end = get_past_7_days_range()
876
+ print(f"过去7天范围: {start} 到 {end}")
877
+
878
+ # 测试时间戳转换
879
+ current_ts = int(datetime.now().timestamp() * 1000)
880
+ print(f"当前时间戳: {current_ts}")
881
+ print(f"时间戳转字符串: {convert_timestamp_to_str(current_ts)}")
882
+ print(f"时间戳转日期: {convert_timestamp_to_date(current_ts)}")