datetime_func.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import datetime
  2. from dateutil import tz
  3. import time
  4. from functools import wraps
  5. import traceback
  6. import sys
  7. import threading
  8. # 获取带上海时区的当前时间,可指定以天为单位的延时,用于本地历史数据测试
  9. def get_now(delay_day=0):
  10. """
  11. :param delay_day: int 表示延时天数,只有测试历史数据时使用
  12. :return: datetime
  13. """
  14. return datetime.datetime.now(tz=tz.gettz('Asia/Shanghai')) - datetime.timedelta(days=delay_day)
  15. # decorator 使被修饰任务整点运行,并处理异常
  16. def timed_exec(intv_timed: datetime.timedelta, round_mode, sleep=60):
  17. """
  18. 被修饰任务的第一个参数必须为 now
  19. 且修饰后不用再向任务传入该参数,由装饰器向任务传送整点时间
  20. :param intv_timed: timedelta 运行的时间间隔
  21. :param round_mode: str 时间的取整方式
  22. 支持 {None, 'sec', 'min', 'hou', 'day', '10min', '30min'}
  23. :param sleep: int=60 当指定间隔未到,或出现异常,休眠指定时间,以秒为单位
  24. :return: function
  25. """
  26. def timed_exec_deco(func):
  27. @wraps(func)
  28. def timed_execute_wraps(*args, **kwargs):
  29. now = round_time(get_now(), round_mode) - intv_timed
  30. while True:
  31. try:
  32. now = round_time(time_block(now, intv_timed, sleep=sleep), round_mode)
  33. func(now, *args, **kwargs)
  34. except Exception as e:
  35. print()
  36. print(f"{datetime.datetime.now()}:")
  37. print(f"when run {now} task an error occur!")
  38. print(f"Exception Info:")
  39. e_type, e_value, e_traceback = sys.exc_info()
  40. print(e_type)
  41. print(e_value)
  42. traceback.print_tb(e_traceback)
  43. print()
  44. time.sleep(sleep)
  45. return timed_execute_wraps
  46. return timed_exec_deco
  47. # decorator 使被修饰任务整点运行,并处理异常,且告知任务这次和上次的时间
  48. def timed_exec_last_now(intv_timed: datetime.timedelta, round_mode, bg_last_now='auto', sleep=60):
  49. """
  50. 被修饰任务的前两个参数必须为 now,last_now,分别为本次运行时间和上次运行时间
  51. 且修饰后不用再向任务传入该参数,由装饰器向任务传送两个时间
  52. :param intv_timed: timedelta 运行的时间间隔
  53. :param round_mode: str 时间的取整方式
  54. 支持 {None, 'sec', 'min', 'hou', 'day', '10min', '30min'}
  55. :param bg_last_now: datetime 第一次执行时给的 last_now
  56. default='auto' 自动向前减去 intv_timed 作为 last_now
  57. :param sleep: int=60 当指定间隔未到,或出现异常,休眠指定时间,以秒为单位
  58. :return: function
  59. """
  60. def timed_exec_deco(func):
  61. @wraps(func)
  62. def timed_execute_wraps(*args, **kwargs):
  63. if bg_last_now == 'auto':
  64. last_now = round_time(get_now(), round_mode) - intv_timed
  65. else:
  66. last_now = bg_last_now
  67. while True:
  68. try:
  69. now = round_time(time_block(last_now, intv_timed, sleep=sleep), round_mode)
  70. func(now, last_now, *args, **kwargs)
  71. last_now = now
  72. except Exception as e:
  73. print()
  74. print(f"{datetime.datetime.now()}:")
  75. print(f"when run {now} task an error occur!")
  76. print(f"Exception Info:")
  77. e_type, e_value, e_traceback = sys.exc_info()
  78. print(e_type)
  79. print(e_value)
  80. traceback.print_tb(e_traceback)
  81. print()
  82. time.sleep(sleep)
  83. return timed_execute_wraps
  84. return timed_exec_deco
  85. # decorator 使被修饰任务整点运行,并处理异常,且在出错时会打印线程信息
  86. def timed_exec_multhd(intv_timed: datetime.timedelta, round_mode, sleep=60):
  87. """
  88. 被修饰任务的第一个参数必须为 now
  89. 且修饰后不用再向任务传入该参数,由装饰器向任务传送整点时间
  90. :param intv_timed: timedelta 运行的时间间隔
  91. :param round_mode: str 时间的取整方式
  92. 支持 {None, 'sec', 'min', 'hou', 'day', '10min', '30min'}
  93. :param sleep: int=60 当指定间隔未到,或出现异常,休眠指定时间,以秒为单位
  94. :return: function
  95. """
  96. def timed_exec_deco(func):
  97. @wraps(func)
  98. def timed_execute_wraps(*args, **kwargs):
  99. now = round_time(get_now(), round_mode) - intv_timed
  100. while True:
  101. try:
  102. now = round_time(time_block(now, intv_timed, sleep=sleep), round_mode)
  103. func(now, *args, **kwargs)
  104. except Exception as e:
  105. thread_curr = threading.currentThread()
  106. print()
  107. print(f"{datetime.datetime.now()}:")
  108. print(f"In {thread_curr.name} (target: {thread_curr._target}, args: {thread_curr._args})")
  109. print(f"when run {now} task an error occur!")
  110. print(f"Exception Info:")
  111. e_type, e_value, e_traceback = sys.exc_info()
  112. print(e_type)
  113. print(e_value)
  114. traceback.print_tb(e_traceback)
  115. print()
  116. time.sleep(sleep)
  117. return timed_execute_wraps
  118. return timed_exec_deco
  119. # 对 datetime 向前取整
  120. def round_time(t_: datetime.datetime, lvl=None):
  121. """
  122. :param t_: datetime
  123. :param lvl: str=None 取整方式,目前支持
  124. {None, 'sec', 'min', 'hou', 'day', '10min', '30min'}
  125. :return: datetime or "No support"
  126. """
  127. if lvl is None:
  128. return t_
  129. round_lvl = "round_" + lvl
  130. if round_lvl in globals():
  131. return globals()[round_lvl](t_)
  132. else:
  133. return "No support"
  134. def round_sec(t_: datetime.datetime):
  135. return t_ - datetime.timedelta(microseconds=t_.microsecond)
  136. def round_min(t_: datetime.datetime):
  137. return round_sec(t_) - datetime.timedelta(seconds=t_.second)
  138. def round_hou(t_: datetime.datetime):
  139. return round_min(t_) - datetime.timedelta(minutes=t_.minute)
  140. def round_day(t_: datetime.datetime):
  141. return round_hou(t_) - datetime.timedelta(hours=t_.hour)
  142. def round_10min(t_: datetime.datetime):
  143. t_ = round_min(t_)
  144. return t_ - datetime.timedelta(minutes=t_.minute % 10)
  145. def round_30min(t_: datetime.datetime):
  146. t_ = round_min(t_)
  147. if t_.minute < 30:
  148. return t_ - datetime.timedelta(minutes=t_.minute)
  149. else:
  150. return t_ - datetime.timedelta(minutes=t_.minute - 30)
  151. # 半成品的时间比较函数
  152. def time_check(t_, st, timed_thre):
  153. if t_ - st >= timed_thre:
  154. return True
  155. else:
  156. return False
  157. # 阻塞并不断检查,直到当前时间和指定时间的差大于指定间隔时,释放并返回当前时间
  158. def time_block(t_: datetime.datetime, timed_thre: datetime.timedelta, sleep=1):
  159. while True:
  160. now = get_now()
  161. if now - t_ >= timed_thre:
  162. return now
  163. else:
  164. time.sleep(sleep)