tc_cron.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. #pragma once
  2. #include <mutex>
  3. #include <condition_variable>
  4. #include <unordered_map>
  5. #include <unordered_set>
  6. #include <map>
  7. #include <bitset>
  8. #include "util/tc_common.h"
  9. #include "util/tc_ex.h"
  10. #include <ctime>
  11. namespace tars
  12. {
  13. struct TC_CronException : public TC_Exception
  14. {
  15. public:
  16. TC_CronException(const string& buffer) : TC_Exception(buffer) {};
  17. // TC_CronException(const string& buffer, bool err) : TC_Exception(buffer, err) {};
  18. ~TC_CronException() throw() {};
  19. };
  20. typedef uint8_t cron_int;
  21. class TC_Cron
  22. {
  23. public:
  24. enum class CronField
  25. {
  26. second,
  27. minute,
  28. hour_of_day,
  29. day_of_week,
  30. day_of_month,
  31. month,
  32. year
  33. };
  34. static const std::time_t INVALID_TIME = static_cast<std::time_t>(-1);
  35. static const size_t INVALID_INDEX = static_cast<size_t>(-1);
  36. public:
  37. /**
  38. * @brief 创建一个cron对象
  39. * @return cron 对象
  40. */
  41. // 字段分别为 <seconds> <minutes> <hours> <days of month> <months> <days of week>
  42. // 通配符以及含义
  43. // * all values selects all values within a field
  44. // - range specify ranges
  45. // , comma specify additional values
  46. // / slash speficy increments
  47. // DAYS = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
  48. // MONTHS = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
  49. // 各类例子
  50. // CRON Description
  51. // * * * * * * Every second
  52. // */5 * * * * * Every 5 seconds
  53. // 0 */5 */2 * * * Every 5 minutes, every 2 hours
  54. // 0 */2 */2 * */2 */2 Every 2 minutes, every 2 hours, every 2 days of the week, every 2 months
  55. // 0 15 10 * * * * 10:15 AM every day
  56. // 0 0/5 14 * * * Every 5 minutes starting at 2 PM and ending at 2:55 PM, every day
  57. // 0 10,44 14 * 3 WED 2:10 PM and at 2:44 PM every Wednesday of March
  58. // 0 15 10 * * MON-FRI 10:15 AM every Monday, Tuesday, Wednesday, Thursday and Friday
  59. // 0 0 12 1/5 * * 12 PM every 5 days every month, starting on the first day of the month
  60. // 0 11 11 11 11 * Every November 11th at 11:11 AM
  61. static TC_Cron makecron(const string & expr);
  62. /**
  63. * @brief 获取cron对象的下一个时间点
  64. * @param cron 对象
  65. * @return 如果返回 INVALID_TIME,则是错误时间,否则返回正确的时间戳
  66. */
  67. static std::time_t nextcron( const TC_Cron& cron, std::time_t timestamp);
  68. /**
  69. * @brief 获取cron对象的下一个时间点
  70. * @param cron 对象
  71. * @return 如果返回 INVALID_TIME,则是错误时间,否则返回正确的时间戳
  72. */
  73. static std::time_t nextcron(const TC_Cron& cron);
  74. public:
  75. std::bitset<60> seconds;
  76. std::bitset<60> minutes;
  77. std::bitset<24> hours;
  78. std::bitset<7> days_of_week;
  79. std::bitset<31> days_of_month;
  80. std::bitset<12> months;
  81. bool isset = false;
  82. public:
  83. static const cron_int CRON_MIN_SECONDS = 0;
  84. static const cron_int CRON_MAX_SECONDS = 59;
  85. static const cron_int CRON_MIN_MINUTES = 0;
  86. static const cron_int CRON_MAX_MINUTES = 59;
  87. static const cron_int CRON_MIN_HOURS = 0;
  88. static const cron_int CRON_MAX_HOURS = 23;
  89. static const cron_int CRON_MIN_DAYS_OF_WEEK = 0;
  90. static const cron_int CRON_MAX_DAYS_OF_WEEK = 6;
  91. static const cron_int CRON_MIN_DAYS_OF_MONTH = 1;
  92. static const cron_int CRON_MAX_DAYS_OF_MONTH = 31;
  93. static const cron_int CRON_MIN_MONTHS = 1;
  94. static const cron_int CRON_MAX_MONTHS = 12;
  95. static const cron_int CRON_MAX_YEARS_DIFF = 4;
  96. static const std::vector<std::string> DAYS;
  97. static const std::vector<std::string> MONTHS;
  98. protected:
  99. /**
  100. * @brief 判断是否包含字符
  101. * @return true 包含;false 不包含
  102. */
  103. static bool contains(const std::string &text, char ch) ;
  104. /**
  105. * @brief 转换成crontab合法数字
  106. * @return cron_int
  107. */
  108. static cron_int to_cron_int(const std::string& text);
  109. /**
  110. * @brief 时间格式转换函数
  111. */
  112. static std::time_t tm_to_time(std::tm& tmt);
  113. static std::tm* time_to_tm(std::time_t const* date, std::tm* const out);
  114. protected:
  115. /**
  116. * @brief 替换周/月的字符为下标
  117. */
  118. static std::string replaceOrdinals(std::string text, const std::vector<std::string> & replacement);
  119. /**
  120. * @brief 获取时间范围,用于计算通配符
  121. */
  122. static std::pair<cron_int, cron_int> makeRange(std::string field, cron_int minval, cron_int maxval);
  123. /**
  124. * @brief 设置crontab不同的位置标记
  125. */
  126. template <size_t N>
  127. static void setCronField(std::string value, std::bitset<N>& target, cron_int minval, cron_int maxval);
  128. static void setCronDaysOfWeek(std::string value, std::bitset<7>& target);
  129. static void setCronDaysOfMonth(std::string value, std::bitset<31>& target);
  130. static void setCronMonth(std::string value, std::bitset<12>& target);
  131. /**
  132. * @brief 计算下一个时间戳
  133. */
  134. template <size_t N>
  135. static size_t findNext(const std::bitset<N> & target, std::tm& tmt, unsigned int minimum, unsigned int maximum, unsigned int value,
  136. CronField field, CronField next_field, const std::bitset<7> & marked_fields);
  137. static bool findNext(const TC_Cron & cron, std::tm& tmt, size_t dot);
  138. static size_t findNextDay(std::tm& tmt,std::bitset<31> const& days_of_month,size_t day_of_month,const std::bitset<7> & days_of_week,size_t day_of_week,const std::bitset<7> & marked_fields);
  139. /**
  140. * @brief 位图控制函数
  141. */
  142. template <size_t N>
  143. static size_t nextSetbit(const std::bitset<N> & target, size_t minimum, size_t maximum, size_t offset);
  144. static void addToField(std::tm& tmt, CronField field, int val);
  145. static void setField(std::tm& tmt, CronField field, int val);
  146. static void resetField(std::tm& tmt, CronField field);
  147. static void resetAllFields(std::tm& tmt, const std::bitset<7> & marked_fields);
  148. static void markField(std::bitset<7>& orders, CronField field);
  149. };
  150. template <size_t N>
  151. void TC_Cron::setCronField(std::string value,std::bitset<N>& target,cron_int minval,cron_int maxval)
  152. {
  153. if (value.length() > 0 && value[value.length() - 1] == ',')
  154. throw TC_CronException("[TC_Cron::setCronField] value cannot end with comma");
  155. auto fields = TC_Common::sepstr<string>(value, ",");
  156. if (fields.empty())
  157. throw TC_CronException("[TC_Cron::setCronField] expression parsing error");
  158. for (auto const& field : fields)
  159. {
  160. if (!contains(field, '/'))
  161. {
  162. auto item = makeRange(field, minval, maxval);
  163. auto first = item.first;
  164. auto last = item.second;
  165. for (cron_int i = first - minval; i <= last - minval; ++i)
  166. {
  167. target.set(i);
  168. }
  169. }
  170. else
  171. {
  172. auto parts = TC_Common::sepstr<string>(field, "/");
  173. if (parts.size() != 2)
  174. throw TC_CronException("[TC_Cron::setCronField] incrementer must have two fields");
  175. auto item = makeRange(parts[0], minval, maxval);
  176. auto first = item.first;
  177. auto last = item.second;
  178. if (!contains(parts[0], '-'))
  179. {
  180. last = maxval;
  181. }
  182. auto delta = to_cron_int(parts[1]);
  183. if (delta <= 0)
  184. throw TC_CronException("[TC_Cron::setCronField] incrementer must be a positive value");
  185. for (cron_int i = first - minval; i <= last - minval; i += delta)
  186. {
  187. target.set(i);
  188. }
  189. }
  190. }
  191. }
  192. template <size_t N>
  193. size_t TC_Cron::nextSetbit(const std::bitset<N> & target,size_t minimum,size_t maximum,size_t offset)
  194. {
  195. for (auto i = offset; i < N; ++i)
  196. {
  197. if (target.test(i)) return i;
  198. }
  199. return INVALID_INDEX;
  200. }
  201. template <size_t N>
  202. size_t TC_Cron::findNext(const std::bitset<N> & target, std::tm& tmt, unsigned int minimum, unsigned int maximum, unsigned int value,
  203. CronField field, CronField next_field, const std::bitset<7> & marked_fields)
  204. {
  205. auto next_value = nextSetbit(target, minimum, maximum, value);
  206. if (INVALID_INDEX == next_value)
  207. {
  208. addToField(tmt, next_field, 1);
  209. resetField(tmt, field);
  210. next_value = nextSetbit(target, minimum, maximum, 0);
  211. }
  212. if (INVALID_INDEX == next_value || next_value != value)
  213. {
  214. setField(tmt, field, static_cast<int>(next_value));
  215. resetAllFields(tmt, marked_fields);
  216. }
  217. return next_value;
  218. }
  219. }