qrpa 1.0.34__py3-none-any.whl → 1.1.50__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.
- qrpa/RateLimitedSender.py +45 -45
- qrpa/__init__.py +31 -26
- qrpa/db_migrator.py +600 -600
- qrpa/feishu_bot_app.py +267 -267
- qrpa/feishu_client.py +410 -0
- qrpa/feishu_logic.py +1443 -0
- qrpa/fun_base.py +339 -337
- qrpa/fun_excel.py +529 -61
- qrpa/fun_file.py +318 -318
- qrpa/fun_web.py +258 -148
- qrpa/fun_win.py +198 -198
- qrpa/mysql_module/__init__.py +0 -0
- qrpa/mysql_module/new_product_analysis_model.py +556 -0
- qrpa/mysql_module/shein_ledger_model.py +468 -0
- qrpa/mysql_module/shein_product_model.py +495 -0
- qrpa/mysql_module/shein_return_order_model.py +569 -0
- qrpa/mysql_module/shein_store_model.py +595 -0
- qrpa/shein_daily_report_model.py +375 -375
- qrpa/shein_excel.py +1248 -109
- qrpa/shein_lib.py +2333 -143
- qrpa/shein_mysql.py +92 -0
- qrpa/shein_sqlite.py +153 -153
- qrpa/shein_ziniao.py +529 -450
- qrpa/temu_chrome.py +56 -56
- qrpa/temu_excel.py +139 -139
- qrpa/temu_lib.py +156 -154
- qrpa/time_utils.py +87 -50
- qrpa/time_utils_example.py +243 -243
- qrpa/wxwork.py +318 -318
- {qrpa-1.0.34.dist-info → qrpa-1.1.50.dist-info}/METADATA +1 -1
- qrpa-1.1.50.dist-info/RECORD +33 -0
- qrpa-1.0.34.dist-info/RECORD +0 -24
- {qrpa-1.0.34.dist-info → qrpa-1.1.50.dist-info}/WHEEL +0 -0
- {qrpa-1.0.34.dist-info → qrpa-1.1.50.dist-info}/top_level.txt +0 -0
qrpa/time_utils.py
CHANGED
|
@@ -8,7 +8,6 @@ import calendar
|
|
|
8
8
|
from datetime import date, datetime, timedelta, timezone
|
|
9
9
|
from typing import Optional, Tuple, List, Union
|
|
10
10
|
|
|
11
|
-
|
|
12
11
|
class TimeUtils:
|
|
13
12
|
"""时间工具类,提供各种时间相关的静态方法"""
|
|
14
13
|
|
|
@@ -94,6 +93,17 @@ class TimeUtils:
|
|
|
94
93
|
last_month = today.month - 1 if today.month > 1 else 12
|
|
95
94
|
return last_month
|
|
96
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
|
+
|
|
97
107
|
# ==================== 日期范围计算 ====================
|
|
98
108
|
|
|
99
109
|
@staticmethod
|
|
@@ -149,6 +159,34 @@ class TimeUtils:
|
|
|
149
159
|
|
|
150
160
|
return start_date.strftime(format_str), end_date.strftime(format_str)
|
|
151
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
|
+
|
|
152
190
|
@staticmethod
|
|
153
191
|
def get_past_nth_day(n: int, start_from: Optional[str] = None, format_str: str = '%Y-%m-%d') -> str:
|
|
154
192
|
"""
|
|
@@ -260,15 +298,27 @@ class TimeUtils:
|
|
|
260
298
|
|
|
261
299
|
@staticmethod
|
|
262
300
|
def get_dates_from_first_of_month_to_yesterday() -> List[str]:
|
|
263
|
-
"""获取从本月第一天到昨天的日期列表
|
|
301
|
+
"""获取从本月第一天到昨天的日期列表
|
|
302
|
+
如果今天是本月第一天,则返回上个月的日期列表
|
|
303
|
+
"""
|
|
264
304
|
today = datetime.today()
|
|
265
|
-
first_day_of_month = today.replace(day=1)
|
|
266
305
|
yesterday = today - timedelta(days=1)
|
|
267
306
|
|
|
268
|
-
|
|
269
|
-
|
|
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
|
|
270
318
|
|
|
271
|
-
|
|
319
|
+
date_list = []
|
|
320
|
+
current_date = start_date
|
|
321
|
+
while current_date <= end_date:
|
|
272
322
|
date_list.append(current_date.strftime('%Y-%m-%d'))
|
|
273
323
|
current_date += timedelta(days=1)
|
|
274
324
|
|
|
@@ -288,6 +338,24 @@ class TimeUtils:
|
|
|
288
338
|
|
|
289
339
|
return first_day.strftime("%Y-%m-%d"), last_day.strftime("%Y-%m-%d")
|
|
290
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
|
+
|
|
291
359
|
@staticmethod
|
|
292
360
|
def get_last_month_range_time_str() -> Tuple[str, str]:
|
|
293
361
|
"""获取上个月第一天和最后一天的时间字符串"""
|
|
@@ -318,6 +386,17 @@ class TimeUtils:
|
|
|
318
386
|
|
|
319
387
|
return start_timestamp, end_timestamp
|
|
320
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
|
+
|
|
321
400
|
@staticmethod
|
|
322
401
|
def is_in_month(time_str: str, month: int, fmt: str = "%Y-%m-%d") -> bool:
|
|
323
402
|
"""
|
|
@@ -561,7 +640,7 @@ class TimeUtils:
|
|
|
561
640
|
return create_time.date() == yesterday.date()
|
|
562
641
|
|
|
563
642
|
@staticmethod
|
|
564
|
-
def is_yesterday_date(date_str: str) -> bool:
|
|
643
|
+
def is_yesterday_date(date_str: str, format="%Y-%m-%d") -> bool:
|
|
565
644
|
"""
|
|
566
645
|
判断给定的日期字符串是否是昨天
|
|
567
646
|
|
|
@@ -572,7 +651,7 @@ class TimeUtils:
|
|
|
572
651
|
如果 date_str 是昨天的日期,返回 True,否则返回 False
|
|
573
652
|
"""
|
|
574
653
|
try:
|
|
575
|
-
create_time = datetime.strptime(date_str,
|
|
654
|
+
create_time = datetime.strptime(date_str, format)
|
|
576
655
|
dt = datetime.now()
|
|
577
656
|
except ValueError:
|
|
578
657
|
raise ValueError("时间字符串格式不正确,请使用正确的格式:'%Y-%m-%d'")
|
|
@@ -607,7 +686,6 @@ class TimeUtils:
|
|
|
607
686
|
|
|
608
687
|
return mtime_dt.strftime('%Y-%m-%d %H:%M:%S') if to_str else mtime_dt
|
|
609
688
|
|
|
610
|
-
|
|
611
689
|
# ==================== 便捷函数 ====================
|
|
612
690
|
# 为了保持向后兼容,提供一些便捷函数
|
|
613
691
|
|
|
@@ -615,197 +693,158 @@ def get_current_date() -> str:
|
|
|
615
693
|
"""获取当前日期,格式为 YYYYMMDD"""
|
|
616
694
|
return TimeUtils.get_current_date()
|
|
617
695
|
|
|
618
|
-
|
|
619
696
|
def get_current_datetime() -> str:
|
|
620
697
|
"""获取当前日期时间,格式为 YYYYMMDDHHMMSS"""
|
|
621
698
|
return TimeUtils.get_current_datetime()
|
|
622
699
|
|
|
623
|
-
|
|
624
700
|
def current_datetime() -> str:
|
|
625
701
|
"""获取当前日期时间,格式为 YYYY-MM-DD HH:MM:SS"""
|
|
626
702
|
return TimeUtils.current_datetime()
|
|
627
703
|
|
|
628
|
-
|
|
629
704
|
def today_date() -> str:
|
|
630
705
|
"""获取今天的日期,格式为 YYYY-MM-DD"""
|
|
631
706
|
return TimeUtils.today_date()
|
|
632
707
|
|
|
633
|
-
|
|
634
708
|
def today_date_hour() -> str:
|
|
635
709
|
"""获取今天的日期和小时,格式为 YYYY-MM-DD_HH"""
|
|
636
710
|
return TimeUtils.today_date_hour()
|
|
637
711
|
|
|
638
|
-
|
|
639
712
|
def get_yesterday(dt: Optional[str] = None) -> str:
|
|
640
713
|
"""获取昨天的日期"""
|
|
641
714
|
return TimeUtils.get_yesterday(dt)
|
|
642
715
|
|
|
643
|
-
|
|
644
716
|
def tomorrow_date() -> str:
|
|
645
717
|
"""获取明天的日期"""
|
|
646
718
|
return TimeUtils.tomorrow_date()
|
|
647
719
|
|
|
648
|
-
|
|
649
720
|
def before_yesterday() -> str:
|
|
650
721
|
"""获取前天的日期"""
|
|
651
722
|
return TimeUtils.before_yesterday()
|
|
652
723
|
|
|
653
|
-
|
|
654
724
|
def get_current_year() -> int:
|
|
655
725
|
"""获取当前年份"""
|
|
656
726
|
return TimeUtils.get_current_year()
|
|
657
727
|
|
|
658
|
-
|
|
659
728
|
def get_current_month() -> int:
|
|
660
729
|
"""获取当前月份"""
|
|
661
730
|
return TimeUtils.get_current_month()
|
|
662
731
|
|
|
663
|
-
|
|
664
732
|
def get_last_month() -> int:
|
|
665
733
|
"""获取上个月的月份"""
|
|
666
734
|
return TimeUtils.get_last_month()
|
|
667
735
|
|
|
668
|
-
|
|
669
736
|
def get_week_num() -> int:
|
|
670
737
|
"""获取当前是第几周"""
|
|
671
738
|
return TimeUtils.get_week_num()
|
|
672
739
|
|
|
673
|
-
|
|
674
740
|
def get_period() -> str:
|
|
675
741
|
"""获取当前时间段(上午/下午/晚上)"""
|
|
676
742
|
return TimeUtils.get_period()
|
|
677
743
|
|
|
678
|
-
|
|
679
744
|
def get_period2() -> str:
|
|
680
745
|
"""获取当前时间段(AM/PM)"""
|
|
681
746
|
return TimeUtils.get_period2()
|
|
682
747
|
|
|
683
|
-
|
|
684
748
|
def get_chinese_weekday(date_str: str) -> str:
|
|
685
749
|
"""根据输入的日期字符串返回中文星期几"""
|
|
686
750
|
return TimeUtils.get_chinese_weekday(date_str)
|
|
687
751
|
|
|
688
|
-
|
|
689
752
|
def get_weekday_name(date_str: str) -> str:
|
|
690
753
|
"""获取中文星期名称(简短格式)"""
|
|
691
754
|
return TimeUtils.get_weekday_name(date_str)
|
|
692
755
|
|
|
693
|
-
|
|
694
756
|
def is_in_month(time_str: str, month: int, fmt: str = "%Y-%m-%d") -> bool:
|
|
695
757
|
"""判断时间字符串是否在指定月份"""
|
|
696
758
|
return TimeUtils.is_in_month(time_str, month, fmt)
|
|
697
759
|
|
|
698
|
-
|
|
699
760
|
def date_trans(d_t: str) -> str:
|
|
700
761
|
"""无斜杠日期转成有斜杠日期"""
|
|
701
762
|
return TimeUtils.date_trans(d_t)
|
|
702
763
|
|
|
703
|
-
|
|
704
764
|
def is_date_greater_or_equal(date_str: str) -> bool:
|
|
705
765
|
"""比较指定日期是否大于或等于今天的日期"""
|
|
706
766
|
return TimeUtils.is_date_greater_or_equal(date_str)
|
|
707
767
|
|
|
708
|
-
|
|
709
768
|
def is_yesterday(create_time_str: str, dt: Optional[str] = None) -> bool:
|
|
710
769
|
"""判断给定的时间字符串是否是昨天"""
|
|
711
770
|
return TimeUtils.is_yesterday(create_time_str, dt)
|
|
712
771
|
|
|
713
|
-
|
|
714
772
|
def is_yesterday_date(date_str: str) -> bool:
|
|
715
773
|
"""判断给定的日期字符串是否是昨天"""
|
|
716
774
|
return TimeUtils.is_yesterday_date(date_str)
|
|
717
775
|
|
|
718
|
-
|
|
719
776
|
def get_file_mtime(file_path: str, to_str: bool = True, tz_offset: int = 8) -> Union[str, datetime]:
|
|
720
777
|
"""获取文件的修改时间"""
|
|
721
778
|
return TimeUtils.get_file_mtime(file_path, to_str, tz_offset)
|
|
722
779
|
|
|
723
|
-
|
|
724
780
|
def convert_timestamp_to_str(timestamp_ms: Optional[int]) -> str:
|
|
725
781
|
"""将毫秒时间戳转换为字符串"""
|
|
726
782
|
return TimeUtils.convert_timestamp_to_str(timestamp_ms)
|
|
727
783
|
|
|
728
|
-
|
|
729
784
|
def convert_timestamp_to_date(timestamp_ms: Union[int, float]) -> str:
|
|
730
785
|
"""将毫秒时间戳转换为日期字符串"""
|
|
731
786
|
return TimeUtils.convert_timestamp_to_date(timestamp_ms)
|
|
732
787
|
|
|
733
|
-
|
|
734
788
|
def convert_datetime_to_date(datetime_str: str) -> str:
|
|
735
789
|
"""将格式为 'YYYY-MM-DD HH:MM:SS' 的时间字符串转换为 'YYYY-MM-DD' 格式的日期字符串"""
|
|
736
790
|
return TimeUtils.convert_datetime_to_date(datetime_str)
|
|
737
791
|
|
|
738
|
-
|
|
739
792
|
def get_current_year_range() -> Tuple[str, str]:
|
|
740
793
|
"""获取当前年份的开始和结束日期"""
|
|
741
794
|
return TimeUtils.get_current_year_range()
|
|
742
795
|
|
|
743
|
-
|
|
744
796
|
def get_start_timestamps(date_str: str) -> int:
|
|
745
797
|
"""获取指定日期的开始毫秒时间戳(00:00:00.000)"""
|
|
746
798
|
return TimeUtils.get_start_timestamps(date_str)
|
|
747
799
|
|
|
748
|
-
|
|
749
800
|
def get_end_timestamps(date_str: str) -> int:
|
|
750
801
|
"""获取指定日期的结束毫秒时间戳(23:59:59.999)"""
|
|
751
802
|
return TimeUtils.get_end_timestamps(date_str)
|
|
752
803
|
|
|
753
|
-
|
|
754
804
|
def format_date_cross_platform(date_str: str) -> str:
|
|
755
805
|
"""跨平台格式化日期"""
|
|
756
806
|
return TimeUtils.format_date_cross_platform(date_str)
|
|
757
807
|
|
|
758
|
-
|
|
759
808
|
def get_past_7_days_range(start_from: Optional[str] = None) -> Tuple[str, str]:
|
|
760
809
|
"""获取过去7天的日期范围(包括结束日,共7天)"""
|
|
761
810
|
return TimeUtils.get_past_7_days_range(start_from)
|
|
762
811
|
|
|
763
|
-
|
|
764
812
|
def get_past_7_days_range_format(start_from: Optional[str] = None, format_str: str = '%Y-%m-%d') -> Tuple[str, str]:
|
|
765
813
|
"""获取过去7天的日期范围(包括结束日,共7天),支持自定义格式"""
|
|
766
814
|
return TimeUtils.get_past_7_days_range_format(start_from, format_str)
|
|
767
815
|
|
|
768
|
-
|
|
769
816
|
def get_past_nth_day(n: int, start_from: Optional[str] = None) -> str:
|
|
770
817
|
"""获取过去第n天的日期"""
|
|
771
818
|
return TimeUtils.get_past_nth_day(n, start_from)
|
|
772
819
|
|
|
773
|
-
|
|
774
820
|
def get_past_n_days_list(n: int, start_from: Optional[str] = None) -> List[str]:
|
|
775
821
|
"""获取过去n天的日期列表,从最旧到最近的日期"""
|
|
776
822
|
return TimeUtils.get_past_n_days_list(n, start_from)
|
|
777
823
|
|
|
778
|
-
|
|
779
824
|
def get_past_7_days_list(start_from: Optional[str] = None) -> List[str]:
|
|
780
825
|
"""获取过去7天的日期列表(不包含 start_from 当天),共7天"""
|
|
781
826
|
return TimeUtils.get_past_7_days_list(start_from)
|
|
782
827
|
|
|
783
|
-
|
|
784
828
|
def date_range(start_date: str, end_date: str) -> List[str]:
|
|
785
829
|
"""生成两个日期之间的日期列表"""
|
|
786
830
|
return TimeUtils.date_range(start_date, end_date)
|
|
787
831
|
|
|
788
|
-
|
|
789
832
|
def get_dates_from_first_of_month_to_yesterday() -> List[str]:
|
|
790
833
|
"""获取从本月第一天到昨天的日期列表"""
|
|
791
834
|
return TimeUtils.get_dates_from_first_of_month_to_yesterday()
|
|
792
835
|
|
|
793
|
-
|
|
794
836
|
def get_last_month_range() -> Tuple[str, str]:
|
|
795
837
|
"""获取上个月的第一天和最后一天"""
|
|
796
838
|
return TimeUtils.get_last_month_range()
|
|
797
839
|
|
|
798
|
-
|
|
799
840
|
def get_last_month_range_time_str() -> Tuple[str, str]:
|
|
800
841
|
"""获取上个月第一天和最后一天的时间字符串"""
|
|
801
842
|
return TimeUtils.get_last_month_range_time_str()
|
|
802
843
|
|
|
803
|
-
|
|
804
844
|
def get_last_month_range_time() -> Tuple[int, int]:
|
|
805
845
|
"""获取上个月第一天和最后一天的毫秒级时间戳"""
|
|
806
846
|
return TimeUtils.get_last_month_range_time()
|
|
807
847
|
|
|
808
|
-
|
|
809
848
|
# 为了向后兼容,保留一些旧函数名
|
|
810
849
|
def get_past_7_days_range_old() -> Tuple[str, str]:
|
|
811
850
|
"""获取过去7天的日期范围(旧版本)"""
|
|
@@ -813,7 +852,6 @@ def get_past_7_days_range_old() -> Tuple[str, str]:
|
|
|
813
852
|
start_date = end_date - timedelta(days=6) # 往前推6天为开始日期
|
|
814
853
|
return start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d')
|
|
815
854
|
|
|
816
|
-
|
|
817
855
|
def get_past_7_days_list_old() -> List[str]:
|
|
818
856
|
"""获取过去7天的日期列表(旧版本)"""
|
|
819
857
|
today = datetime.today()
|
|
@@ -822,7 +860,6 @@ def get_past_7_days_list_old() -> List[str]:
|
|
|
822
860
|
for i in range(1, 8)
|
|
823
861
|
]
|
|
824
862
|
|
|
825
|
-
|
|
826
863
|
if __name__ == "__main__":
|
|
827
864
|
# 测试示例
|
|
828
865
|
print(f"当前日期: {today_date()}")
|