cron.py 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. from datetime import datetime, timedelta
  2. from apscheduler.triggers.cron import CronTrigger
  3. # 重写Cron定时
  4. class VbCronTrigger(CronTrigger):
  5. @classmethod
  6. def from_crontab(cls, expr: str, timezone=None):
  7. values = expr.split()
  8. if len(values) != 6 and len(values) != 7:
  9. raise ValueError('Wrong number of fields; got {}, expected 6 or 7'.format(len(values)))
  10. second = values[0]
  11. minute = values[1]
  12. hour = values[2]
  13. if '?' in values[3]:
  14. day = None
  15. elif 'L' in values[5]:
  16. day = f"last {values[5].replace('L', '')}"
  17. elif 'W' in values[3]:
  18. day = cls.__find_recent_workday(int(values[3].split('W')[0]))
  19. else:
  20. day = values[3].replace('L', 'last')
  21. month = values[4]
  22. if '?' in values[5] or 'L' in values[5]:
  23. week = None
  24. elif '#' in values[5]:
  25. week = int(values[5].split('#')[1])
  26. else:
  27. week = values[5]
  28. if '#' in values[5]:
  29. day_of_week = int(values[5].split('#')[0]) - 1
  30. else:
  31. day_of_week = None
  32. year = values[6] if len(values) == 7 else None
  33. return cls(
  34. second=second,
  35. minute=minute,
  36. hour=hour,
  37. day=day,
  38. month=month,
  39. week=week,
  40. day_of_week=day_of_week,
  41. year=year,
  42. timezone=timezone,
  43. )
  44. @classmethod
  45. def __find_recent_workday(cls, day: int):
  46. now = datetime.now()
  47. date = datetime(now.year, now.month, day)
  48. if date.weekday() < 5:
  49. return date.day
  50. else:
  51. diff = 1
  52. while True:
  53. previous_day = date - timedelta(days=diff)
  54. if previous_day.weekday() < 5:
  55. return previous_day.day
  56. else:
  57. diff += 1