随着目前企业的业务越来越深入,很多业务场景会用到调度任务,例如:某公司需要每天在凌晨的1点生成昨日的数据生产报表,实现的方式有很多,目前运用到最多的则是调度任务,通俗讲就是定时任务,只需要设定好时间,到达该时间点就会自动执行任务,那么这种方式实现的具体原理是怎么样的呢,下面我会分几个层面给大家讲下实现的过程,当然也会把我最近使用的比较好的方式代码贴出来,供大家参考,若大家有更好的方式,也可以下方讨论(^_^)

    定时任务的设定,需要用到Cron表达式,他可以灵活的配置任务的执行时间,具体配置规则大家可以去参考官方Cron的使用规则,也可以尝试在线配置,地址:https://qqe2.com/cron

    这个是整合后的帮助类,里面涵盖了每日 每周 每月等相关定时任务的生成,同时会把执行的时间以集合的形式输出出来。下面我把需要用到的Cron帮助类代码贴出来,供大家参考:

    1. using Newtonsoft.Json.Linq;
    2. using NPOI.SS.Util;
    3. using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
    4. using System;
    5. using System.Collections.Generic;
    6. using System.Linq;
    7. using System.Text;
    8. using System.Threading.Tasks;
    9. namespace CronHelper
    10. {
    11. public class Cron
    12. {
    13. private int[] seconds = new int[60];
    14. private int[] minutes = new int[60];
    15. private int[] hours = new int[24];
    16. private int[] days = new int[31];
    17. private int[] month = new int[12];
    18. private int[] weeks = new int[7];
    19. //2019-2099年
    20. private int[] year = new int[80];
    21. public int[] Seconds { get => seconds; set => seconds = value; }
    22. public int[] Minutes { get => minutes; set => minutes = value; }
    23. public int[] Hours { get => hours; set => hours = value; }
    24. public int[] Days { get => days; set => days = value; }
    25. public int[] Month { get => month; set => month = value; }
    26. public int[] Weeks { get => weeks; set => weeks = value; }
    27. public int[] Year { get => year; set => year = value; }
    28. public Cron()
    29. {
    30. for (int i = 0; i < 60; i++)
    31. {
    32. seconds[i] = 0;
    33. minutes[i] = 0;
    34. }
    35. for (int i = 0; i < 24; i++)
    36. {
    37. hours[i] = 0;
    38. }
    39. for (int i = 0; i < 31; i++)
    40. {
    41. days[i] = 0;
    42. }
    43. for (int i = 0; i < 12; i++)
    44. {
    45. month[i] = 0;
    46. }
    47. for (int i = 0; i < 7; i++)
    48. {
    49. weeks[i] = 0;
    50. }
    51. for (int i = 0; i < 80; i++)
    52. {
    53. year[i] = 0;
    54. }
    55. }
    56. public void Init()
    57. {
    58. for (int i = 0; i < 7; i++)
    59. {
    60. weeks[i] = 0;
    61. }
    62. for (int i = 0; i < 31; i++)
    63. {
    64. days[i] = 0;
    65. }
    66. }
    67. }
    68. /// <summary>
    69. /// 在week上使用 5L表示本月最后一个星期五
    70. /// 7L表示本月最后一个星期天
    71. ///
    72. /// 在week上使用 7#3表示每月的第三个星期天
    73. /// 2#4表示每月的第四个星期二
    74. /// </summary>
    75. public class CronHelper
    76. {
    77. /// <summary>
    78. /// Cron表达式转换(默认开始时间为当前)
    79. /// </summary>
    80. /// <param name="cron">表达式</param>
    81. /// <returns>最近5次要执行的时间</returns>
    82. public static List<DateTime> CronToDateTime(string cron)
    83. {
    84. try
    85. {
    86. List<DateTime> lits = new List<DateTime>();
    87. Cron c = new Cron();
    88. string[] arr = cron.Split(' ');
    89. Seconds(c, arr[0]);
    90. Minutes(c, arr[1]);
    91. Hours(c, arr[2]);
    92. Month(c, arr[4]);
    93. if (arr.Length < 7)
    94. {
    95. Year(c, null);
    96. }
    97. else
    98. {
    99. Year(c, arr[6]);
    100. }
    101. DateTime now = DateTime.Now;
    102. int addtime = 1;
    103. while (true)
    104. {
    105. if (c.Seconds[now.Second] == 1 && c.Minutes[now.Minute] == 1 && c.Hours[now.Hour] == 1 && c.Month[now.Month - 1] == 1 && c.Year[now.Year - 2019] == 1)
    106. {
    107. if (arr[3] != "?")
    108. {
    109. Days(c, arr[3], DateTime.DaysInMonth(now.Year, now.Month), now);
    110. int DayOfWeek = (((int)now.DayOfWeek) + 6) % 7;
    111. if (c.Days[now.Day - 1] == 1 && c.Weeks[DayOfWeek] == 1)
    112. {
    113. lits.Add(now);
    114. }
    115. }
    116. else
    117. {
    118. Weeks(c, arr[5], DateTime.DaysInMonth(now.Year, now.Month), now);
    119. int DayOfWeek = (((int)now.DayOfWeek) + 6) % 7;
    120. if (c.Days[now.Day - 1] == 1 && c.Weeks[DayOfWeek] == 1)
    121. {
    122. lits.Add(now);
    123. }
    124. }
    125. }
    126. if (lits.Count >= 5)
    127. {
    128. break;
    129. }
    130. c.Init();
    131. if (!arr[1].Contains('-') && !arr[1].Contains(',') && !arr[1].Contains('*') && !arr[1].Contains('/'))
    132. {
    133. if (now.Minute == int.Parse(arr[1]))
    134. {
    135. addtime = 3600;
    136. }
    137. }
    138. else if (arr[0] == "0" && now.Second == 0)
    139. {
    140. addtime = 60;
    141. }
    142. now = now.AddSeconds(addtime);
    143. }
    144. return lits;
    145. }
    146. catch
    147. {
    148. return null;
    149. }
    150. }
    151. /// <summary>
    152. /// Cron表达式转换(自定义开始时间)
    153. /// </summary>
    154. /// <param name="cron">表达式</param>
    155. /// <param name="now">开始时间</param>
    156. /// <returns>最近5次要执行的时间</returns>
    157. public static List<DateTime> CronToDateTime(string cron, DateTime now)
    158. {
    159. try
    160. {
    161. List<DateTime> lits = new List<DateTime>();
    162. Cron c = new Cron();
    163. string[] arr = cron.Split(' ');
    164. Seconds(c, arr[0]);
    165. Minutes(c, arr[1]);
    166. Hours(c, arr[2]);
    167. Month(c, arr[4]);
    168. if (arr.Length < 7)
    169. {
    170. Year(c, null);
    171. }
    172. else
    173. {
    174. Year(c, arr[6]);
    175. }
    176. int addtime = 1;
    177. while (true)
    178. {
    179. if (c.Seconds[now.Second] == 1 && c.Minutes[now.Minute] == 1 && c.Hours[now.Hour] == 1 && c.Month[now.Month - 1] == 1 && c.Year[now.Year - 2019] == 1)
    180. {
    181. if (arr[3] != "?")
    182. {
    183. Days(c, arr[3], DateTime.DaysInMonth(now.Year, now.Month), now);
    184. int DayOfWeek = (((int)now.DayOfWeek) + 6) % 7;
    185. if (c.Days[now.Day - 1] == 1 && c.Weeks[DayOfWeek] == 1)
    186. {
    187. lits.Add(now);
    188. }
    189. }
    190. else
    191. {
    192. Weeks(c, arr[5], DateTime.DaysInMonth(now.Year, now.Month), now);
    193. int DayOfWeek = (((int)now.DayOfWeek) + 6) % 7;
    194. if (c.Days[now.Day - 1] == 1 && c.Weeks[DayOfWeek] == 1)
    195. {
    196. lits.Add(now);
    197. }
    198. }
    199. }
    200. if (lits.Count >= 5)
    201. {
    202. break;
    203. }
    204. c.Init();
    205. if (!arr[1].Contains('-') && !arr[1].Contains(',') && !arr[1].Contains('*') && !arr[1].Contains('/'))
    206. {
    207. if (now.Minute == int.Parse(arr[1]))
    208. {
    209. addtime = 3600;
    210. }
    211. }
    212. else if (arr[0] == "0" && now.Second == 0)
    213. {
    214. addtime = 60;
    215. }
    216. now = now.AddSeconds(addtime);
    217. }
    218. return lits;
    219. }
    220. catch
    221. {
    222. return null;
    223. }
    224. }
    225. /// <summary>
    226. /// Cron表达式转换(根据开始时间和结束时间),张鑫
    227. /// </summary>
    228. /// <param name="cron">表达式</param>
    229. /// <param name="now">开始时间</param>
    230. /// <returns>判断开始时间和结束时间截止需要执行的时间</returns>
    231. public static List<DateTime> CronToDateTime(string cron, DateTime now, DateTime endTime)
    232. {
    233. try
    234. {
    235. List<DateTime> lits = new List<DateTime>();
    236. Cron c = new Cron();
    237. string[] arr = cron.Split(' ');
    238. Seconds(c, arr[0]);
    239. Minutes(c, arr[1]);
    240. Hours(c, arr[2]);
    241. Month(c, arr[4]);
    242. if (arr.Length < 7)
    243. {
    244. Year(c, null);
    245. }
    246. else
    247. {
    248. Year(c, arr[6]);
    249. }
    250. int addtime = 1;
    251. while (true)
    252. {
    253. if (c.Seconds[now.Second] == 1 && c.Minutes[now.Minute] == 1 && c.Hours[now.Hour] == 1 && c.Month[now.Month - 1] == 1 && c.Year[now.Year - 2019] == 1)
    254. {
    255. if (arr[3] != "?")
    256. {
    257. Days(c, arr[3], DateTime.DaysInMonth(now.Year, now.Month), now);
    258. int DayOfWeek = (((int)now.DayOfWeek) + 6) % 7;
    259. if (c.Days[now.Day - 1] == 1 && c.Weeks[DayOfWeek] == 1)
    260. {
    261. lits.Add(now);
    262. }
    263. }
    264. else
    265. {
    266. Weeks(c, arr[5], DateTime.DaysInMonth(now.Year, now.Month), now);
    267. int DayOfWeek = (((int)now.DayOfWeek) + 6) % 7;
    268. if (c.Days[now.Day - 1] == 1 && c.Weeks[DayOfWeek] == 1)
    269. {
    270. lits.Add(now);
    271. }
    272. }
    273. }
    274. if (now > endTime)
    275. {
    276. break;
    277. }
    278. c.Init();
    279. if (!arr[1].Contains('-') && !arr[1].Contains(',') && !arr[1].Contains('*') && !arr[1].Contains('/'))
    280. {
    281. if (now.Minute == int.Parse(arr[1]))
    282. {
    283. addtime = 3600;
    284. }
    285. }
    286. else if (arr[0] == "0" && now.Second == 0)
    287. {
    288. addtime = 60;
    289. }
    290. now = now.AddSeconds(addtime);
    291. }
    292. return lits;
    293. }
    294. catch
    295. {
    296. return null;
    297. }
    298. }
    299. /// <summary>
    300. /// Cron表达式转换(默认开始时间为当前)
    301. /// </summary>
    302. /// <param name="cron">表达式</param>
    303. /// <returns>最近要执行的时间字符串</returns>
    304. public static string GetNextDateTime(string cron)
    305. {
    306. try
    307. {
    308. DateTime now = DateTime.Now;
    309. string[] arr = cron.Split(' ');
    310. if (IsOrNoOne(cron))
    311. {
    312. string date = arr[6] + "/" + arr[4] + "/" + arr[3] + " " + arr[2] + ":" + arr[1] + ":" + arr[0];
    313. if (DateTime.Compare(Convert.ToDateTime(date), now) >= 0)
    314. {
    315. return date;
    316. }
    317. else
    318. {
    319. return null;
    320. }
    321. }
    322. Cron c = new Cron();
    323. Seconds(c, arr[0]);
    324. Minutes(c, arr[1]);
    325. Hours(c, arr[2]);
    326. Month(c, arr[4]);
    327. if (arr.Length < 7)
    328. {
    329. Year(c, null);
    330. }
    331. else
    332. {
    333. Year(c, arr[6]);
    334. }
    335. int addtime = 1;
    336. while (true)
    337. {
    338. if (c.Seconds[now.Second] == 1 && c.Minutes[now.Minute] == 1 && c.Hours[now.Hour] == 1 && c.Month[now.Month - 1] == 1 && c.Year[now.Year - 2019] == 1)
    339. {
    340. if (arr[3] != "?")
    341. {
    342. Days(c, arr[3], DateTime.DaysInMonth(now.Year, now.Month), now);
    343. int DayOfWeek = (((int)now.DayOfWeek) + 6) % 7;
    344. if (c.Days[now.Day - 1] == 1 && c.Weeks[DayOfWeek] == 1)
    345. {
    346. return now.ToString("yyyy/MM/dd HH:mm:ss");
    347. }
    348. }
    349. else
    350. {
    351. Weeks(c, arr[5], DateTime.DaysInMonth(now.Year, now.Month), now);
    352. int DayOfWeek = (((int)now.DayOfWeek) + 6) % 7;
    353. if (c.Days[now.Day - 1] == 1 && c.Weeks[DayOfWeek] == 1)
    354. {
    355. return now.ToString("yyyy/MM/dd HH:mm:ss");
    356. }
    357. }
    358. }
    359. c.Init();
    360. if (!arr[1].Contains('-') && !arr[1].Contains(',') && !arr[1].Contains('*') && !arr[1].Contains('/'))
    361. {
    362. if (now.Minute == int.Parse(arr[1]))
    363. {
    364. addtime = 3600;
    365. }
    366. }
    367. else if (arr[0] == "0" && now.Second == 0)
    368. {
    369. addtime = 60;
    370. }
    371. now = now.AddSeconds(addtime);
    372. }
    373. }
    374. catch
    375. {
    376. return null;
    377. }
    378. }
    379. /// <summary>
    380. /// Cron表达式转换(自定义开始时间)
    381. /// </summary>
    382. /// <param name="cron">表达式</param>
    383. /// <param name="now">开始时间</param>
    384. /// <returns>最近要执行的时间字符串</returns>
    385. public static string GetNextDateTime(string cron, DateTime now)
    386. {
    387. try
    388. {
    389. string[] arr = cron.Split(' ');
    390. if (IsOrNoOne(cron))
    391. {
    392. string date = arr[6] + "/" + arr[4] + "/" + arr[3] + " " + arr[2] + ":" + arr[1] + ":" + arr[0];
    393. if (DateTime.Compare(Convert.ToDateTime(date), now) > 0)
    394. {
    395. return date;
    396. }
    397. else
    398. {
    399. return null;
    400. }
    401. }
    402. Cron c = new Cron();
    403. Seconds(c, arr[0]);
    404. Minutes(c, arr[1]);
    405. Hours(c, arr[2]);
    406. Month(c, arr[4]);
    407. if (arr.Length < 7)
    408. {
    409. Year(c, null);
    410. }
    411. else
    412. {
    413. Year(c, arr[6]);
    414. }
    415. int addtime = 1;
    416. while (true)
    417. {
    418. if (c.Seconds[now.Second] == 1 && c.Minutes[now.Minute] == 1 && c.Hours[now.Hour] == 1 && c.Month[now.Month - 1] == 1 && c.Year[now.Year - 2019] == 1)
    419. {
    420. if (arr[3] != "?")
    421. {
    422. Days(c, arr[3], DateTime.DaysInMonth(now.Year, now.Month), now);
    423. int DayOfWeek = (((int)now.DayOfWeek) + 6) % 7;
    424. if (c.Days[now.Day - 1] == 1 && c.Weeks[DayOfWeek] == 1)
    425. {
    426. return now.ToString("yyyy/MM/dd HH:mm:ss");
    427. }
    428. }
    429. else
    430. {
    431. Weeks(c, arr[5], DateTime.DaysInMonth(now.Year, now.Month), now);
    432. int DayOfWeek = (((int)now.DayOfWeek) + 6) % 7;
    433. if (c.Days[now.Day - 1] == 1 && c.Weeks[DayOfWeek] == 1)
    434. {
    435. return now.ToString("yyyy/MM/dd HH:mm:ss");
    436. }
    437. }
    438. }
    439. c.Init();
    440. if (!arr[1].Contains('-') && !arr[1].Contains(',') && !arr[1].Contains('*') && !arr[1].Contains('/'))
    441. {
    442. if (now.Minute == int.Parse(arr[1]))
    443. {
    444. addtime = 3600;
    445. }
    446. }
    447. else if (arr[0] == "0" && now.Second == 0)
    448. {
    449. addtime = 60;
    450. }
    451. now = now.AddSeconds(addtime);
    452. }
    453. }
    454. catch
    455. {
    456. return null;
    457. }
    458. }
    459. /// <summary>
    460. /// 返回周计划中间隔周所有的时间集合
    461. /// </summary>
    462. /// <param name="cron"></param>
    463. /// <param name="startTime"></param>
    464. /// <param name="endTime"></param>
    465. /// <param name="weekNum"></param>
    466. /// <returns></returns>
    467. public static List<DateTime> CheckWeekIsExcute(string cron, DateTime startTime, DateTime endTime, int weekNum)
    468. {
    469. string[] cronArr = cron.Split(' ');
    470. List<DateTime> returnList = new List<DateTime>();
    471. // List<DateTime> newDateList = CronHelper.CronToDateTime(cron, startTime, endTime);
    472. string[] weekDayArr = cronArr[5].Split(',');
    473. foreach (string item in weekDayArr)
    474. {
    475. //间隔周期
    476. int jgIndex = 0;
    477. for (int k = startTime.Month; k <= endTime.Month; k++)
    478. {
    479. //判断默认从开始月份的第一天 获取本月多少天
    480. int allDay = Convert.ToDateTime(startTime.Year + "-" + k + "-01").AddMonths(1).AddDays(-1).Day;
    481. for (int i = 1; i < allDay; i++)
    482. {
    483. //获取默认是几月
    484. string Monthindex = k.ToString().PadLeft(2, '0');
    485. // 获取当前是周几
    486. int dayOfweek = (int)Convert.ToDateTime(startTime.ToString("yyyy-" + Monthindex + "-") + i.ToString().PadLeft(2, '0')).DayOfWeek;
    487. // 获取当前日期
    488. DateTime nowDate = Convert.ToDateTime(startTime.ToString("yyyy-" + Monthindex + "-") + i.ToString().PadLeft(2, '0'));
    489. if (nowDate < startTime.Date)
    490. {
    491. continue;
    492. }
    493. if (nowDate > endTime.Date)
    494. {
    495. break;
    496. }
    497. //表示该日期就可以执行 如果表达式的 周几等于当前周几 或者 表达式的周是周日并且 现在周是0 ’
    498. //获取当前周默认是从周日开始 0-6
    499. if (item == dayOfweek.ToString() || (item == "7" && dayOfweek == 0))
    500. {
    501. if (jgIndex == 0 || jgIndex % weekNum == 0)
    502. {
    503. returnList.Add(nowDate);
    504. }
    505. jgIndex++;
    506. }
    507. }
    508. }
    509. }
    510. //.OrderBy(x => x.Date) .Where(x => x.Date >= startTime.Date).ToList()
    511. return returnList;
    512. }
    513. /// <summary>
    514. /// 返回周计划中间隔周所有的时间集合【跨年】
    515. /// </summary>
    516. /// <param name="cron"></param>
    517. /// <param name="startTime"></param>
    518. /// <param name="endTime"></param>
    519. /// <param name="weekNum"></param>
    520. /// <returns></returns>
    521. public static List<DateTime> CheckWeekIsExcuteNew(string cron, DateTime startTime, DateTime endTime, int weekNum)
    522. {
    523. int weeknum = weekNum;
    524. string[] cronArr = cron.Split(' ');
    525. //存储原来的开始时间
    526. DateTime oldstartTime = startTime;
    527. string[] weekDayArr = cronArr[5].Split(',');
    528. List<DateTime> resList = new List<DateTime>();
    529. int jgIndex = 0;
    530. DateTime startExcuteDate = new DateTime(1899, 01, 01);
    531. foreach (var item in weekDayArr)
    532. {
    533. //重新获取星期几初始化开始日期为传入的日期
    534. startTime = oldstartTime;
    535. while (true)
    536. {
    537. //获取开始时间的月份有多少天
    538. int monthDay = Convert.ToDateTime(startTime.ToString("yyyy-MM-01")).AddMonths(1).AddDays(-1).Day;
    539. for (int i = startTime.Day; i <= monthDay; i++)
    540. {
    541. //判断间隔索引如果大于0则不需要执行循环函数计算执行的开始日期
    542. if (jgIndex > 0)
    543. {
    544. break;
    545. }
    546. //获取当前日期
    547. DateTime nowdate = Convert.ToDateTime(startTime.ToString("yyyy-MM-" + i.ToString().PadLeft(2, '0')));
    548. //获取当前日期是周几 第一天是从周日开始执行的
    549. int week = (int)(nowdate.DayOfWeek);
    550. //判断当前周几和传入的周几比较
    551. if (item == week.ToString() || (item == "7" && week == 0))
    552. {
    553. jgIndex++;
    554. startExcuteDate = nowdate;
    555. resList.Add(startExcuteDate);
    556. break;
    557. }
    558. else if (i == monthDay)//判断是本月的最后一天则还未匹配到需要执行的日期则加一天
    559. {
    560. startTime = startTime.AddDays(1);
    561. }
    562. }
    563. if (jgIndex > 0)
    564. {
    565. //获取到下次需要执行的日期
    566. DateTime nextdate = startExcuteDate.AddDays(jgIndex * weeknum * 7);
    567. //判断执行的日期大于结束日期则终止
    568. if (nextdate > endTime)
    569. {
    570. jgIndex = 0;
    571. startExcuteDate = new DateTime(1899, 01, 01);
    572. break;
    573. }
    574. resList.Add(nextdate);
    575. jgIndex++;
    576. }
    577. }
    578. }
    579. return resList;
    580. }
    581. /// <summary>
    582. /// 根据制定的计划转换成cron表达式,张鑫
    583. /// </summary>
    584. /// <param name="dateJson"></param>
    585. /// <returns></returns>
    586. public static string ConvertToCron(CronModel dateJson)
    587. {
    588. string cron = string.Empty;
    589. string excuteType = dateJson.excuteType;
    590. if (excuteType.IsNotNullOrEmpty())
    591. {
    592. DateTime stDate = Convert.ToDateTime(dateJson.startTime);
    593. //结束日期为空
    594. if (dateJson.endTime.IsNullOrEmpty())
    595. {
    596. dateJson.endTime = "1899-01-01 00:00:00";
    597. }
    598. DateTime enDate = Convert.ToDateTime(dateJson.endTime);
    599. int excuteTimes = Convert.ToInt32(dateJson.excuteTimes);
    600. string excuteMonth = dateJson.excuteMonth;
    601. string excuteMonth_Day = dateJson.excuteMonth_Day;
    602. int excuteWeek = Convert.ToInt32(dateJson.excuteWeek);
    603. string excuteWeek_Day = dateJson.excuteWeek_Day;
    604. switch (excuteType)
    605. {
    606. case "Day":
    607. cron = ConvertToCron(stDate, enDate, excuteTimes);
    608. break;
    609. case "Month":
    610. cron = ConvertToCron(stDate, enDate, excuteMonth, excuteMonth_Day);
    611. break;
    612. case "Week":
    613. cron = ConvertToCron(stDate, enDate, excuteWeek, excuteWeek_Day);
    614. break;
    615. default:
    616. cron = $"0 0 0 {stDate.Day} {stDate.Month} ? {stDate.Year}";
    617. break;
    618. }
    619. }
    620. return cron;
    621. }
    622. /// <summary>
    623. /// 转换为cron表达式日
    624. /// </summary>
    625. /// <param name="startTime"></param>
    626. /// <param name="endTime"></param>
    627. /// <param name=""></param>
    628. /// <returns></returns>
    629. public static string ConvertToCron(DateTime startTime, DateTime endTime, int excuteTimes)
    630. {
    631. Console.WriteLine("调用日生成表达式开始");
    632. string yearCron = "*";
    633. if (endTime.Year != 1899)
    634. {
    635. yearCron = $"{startTime.Year}-{endTime.Year}";
    636. }
    637. string cron = $"{startTime.Second} {startTime.Minute} {startTime.Hour} {startTime.Day}/{excuteTimes} * ? {yearCron}";
    638. Console.WriteLine("调用日生成表达式结束");
    639. return cron;
    640. }
    641. /// <summary>
    642. /// 转换为cron表达式月
    643. /// </summary>
    644. /// <param name="startTime"></param>
    645. /// <param name="endTime"></param>
    646. /// <param name=""></param>
    647. /// <returns></returns>
    648. public static string ConvertToCron(DateTime startTime, DateTime endTime, string excuteMonth, string excuteMonth_Day)
    649. {
    650. Console.WriteLine("调用月生成表达式开始");
    651. string yearCron = "*";
    652. if (endTime.Year != 1899)
    653. {
    654. yearCron = $"{startTime.Year}-{endTime.Year}";
    655. }
    656. string cron = string.Empty;
    657. string monthNum = GetMonthByChinese(excuteMonth);
    658. if (monthNum.Contains("A"))
    659. {
    660. cron = $"{startTime.Second} {startTime.Minute} {startTime.Hour} {excuteMonth_Day} * ? {yearCron}";
    661. }
    662. else
    663. {
    664. cron = $"{startTime.Second} {startTime.Minute} {startTime.Hour} {excuteMonth_Day} {monthNum} ? {yearCron}";
    665. }
    666. Console.WriteLine("调用月生成表达式结束");
    667. return cron;
    668. }
    669. /// <summary>
    670. /// 转换为cron表达式周
    671. /// </summary>
    672. /// <param name="startTime"></param>
    673. /// <param name="endTime"></param>
    674. /// <param name=""></param>
    675. /// <returns></returns>
    676. public static string ConvertToCron(DateTime startTime, DateTime endTime, int excuteWeek, string excuteWeek_Day)
    677. {
    678. Console.WriteLine("调用周生成表达式开始");
    679. string yearCron = "*";
    680. if (endTime.Year != 1899)
    681. {
    682. yearCron = $"{startTime.Year}-{endTime.Year}";
    683. }
    684. string weekNum = GetWeekByChinese(excuteWeek_Day);
    685. string cron = $"{startTime.Second} {startTime.Minute} {startTime.Hour} ? * {weekNum} {yearCron}";
    686. Console.WriteLine("调用周生成表达式结束");
    687. return cron;
    688. }
    689. /// <summary>
    690. /// Cron表达式转换成中文描述
    691. /// </summary>
    692. /// <param name="cronExp"></param>
    693. /// <returns></returns>
    694. public static string TranslateToChinese(string cronExp)
    695. {
    696. if (cronExp == null || cronExp.Length < 1)
    697. {
    698. return "cron表达式为空";
    699. }
    700. string[] tmpCorns = cronExp.Split(" ");
    701. StringBuilder sBuffer = new StringBuilder();
    702. if (tmpCorns.Length == 6)
    703. {
    704. //解析月
    705. if (!tmpCorns[4].Equals("*"))
    706. {
    707. sBuffer.Append(tmpCorns[4]).Append("月");
    708. }
    709. else
    710. {
    711. sBuffer.Append("每月");
    712. }
    713. //解析周
    714. if (!tmpCorns[5].Equals("*") && !tmpCorns[5].Equals("?"))
    715. {
    716. char[] tmpArray = tmpCorns[5].ToCharArray();
    717. foreach (char tmp in tmpArray)
    718. {
    719. switch (tmp)
    720. {
    721. case '1':
    722. sBuffer.Append("星期天");
    723. break;
    724. case '2':
    725. sBuffer.Append("星期一");
    726. break;
    727. case '3':
    728. sBuffer.Append("星期二");
    729. break;
    730. case '4':
    731. sBuffer.Append("星期三");
    732. break;
    733. case '5':
    734. sBuffer.Append("星期四");
    735. break;
    736. case '6':
    737. sBuffer.Append("星期五");
    738. break;
    739. case '7':
    740. sBuffer.Append("星期六");
    741. break;
    742. case '-':
    743. sBuffer.Append("至");
    744. break;
    745. default:
    746. sBuffer.Append(tmp);
    747. break;
    748. }
    749. }
    750. }
    751. //解析日
    752. if (!tmpCorns[3].Equals("?"))
    753. {
    754. if (!tmpCorns[3].Equals("*"))
    755. {
    756. sBuffer.Append(tmpCorns[3]).Append("日");
    757. }
    758. else
    759. {
    760. sBuffer.Append("每日");
    761. }
    762. }
    763. //解析时
    764. if (!tmpCorns[2].Equals("*"))
    765. {
    766. sBuffer.Append(tmpCorns[2]).Append("时");
    767. }
    768. else
    769. {
    770. sBuffer.Append("每时");
    771. }
    772. //解析分
    773. if (!tmpCorns[1].Equals("*"))
    774. {
    775. sBuffer.Append(tmpCorns[1]).Append("分");
    776. }
    777. else
    778. {
    779. sBuffer.Append("每分");
    780. }
    781. //解析秒
    782. if (!tmpCorns[0].Equals("*"))
    783. {
    784. sBuffer.Append(tmpCorns[0]).Append("秒");
    785. }
    786. else
    787. {
    788. sBuffer.Append("每秒");
    789. }
    790. }
    791. return sBuffer.ToString();
    792. }
    793. #region 初始化Cron对象
    794. private static void Seconds(Cron c, string str)
    795. {
    796. if (str == "*")
    797. {
    798. for (int i = 0; i < 60; i++)
    799. {
    800. c.Seconds[i] = 1;
    801. }
    802. }
    803. else if (str.Contains('-'))
    804. {
    805. int begin = int.Parse(str.Split('-')[0]);
    806. int end = int.Parse(str.Split('-')[1]);
    807. for (int i = begin; i <= end; i++)
    808. {
    809. c.Seconds[i] = 1;
    810. }
    811. }
    812. else if (str.Contains('/'))
    813. {
    814. int begin = int.Parse(str.Split('/')[0]);
    815. int interval = int.Parse(str.Split('/')[1]);
    816. while (true)
    817. {
    818. c.Seconds[begin] = 1;
    819. if ((begin + interval) >= 60)
    820. break;
    821. begin += interval;
    822. }
    823. }
    824. else if (str.Contains(','))
    825. {
    826. for (int i = 0; i < str.Split(',').Length; i++)
    827. {
    828. c.Seconds[int.Parse(str.Split(',')[i])] = 1;
    829. }
    830. }
    831. else
    832. {
    833. c.Seconds[int.Parse(str)] = 1;
    834. }
    835. }
    836. private static void Minutes(Cron c, string str)
    837. {
    838. if (str == "*")
    839. {
    840. for (int i = 0; i < 60; i++)
    841. {
    842. c.Minutes[i] = 1;
    843. }
    844. }
    845. else if (str.Contains('-'))
    846. {
    847. int begin = int.Parse(str.Split('-')[0]);
    848. int end = int.Parse(str.Split('-')[1]);
    849. for (int i = begin; i <= end; i++)
    850. {
    851. c.Minutes[i] = 1;
    852. }
    853. }
    854. else if (str.Contains('/'))
    855. {
    856. int begin = int.Parse(str.Split('/')[0]);
    857. int interval = int.Parse(str.Split('/')[1]);
    858. while (true)
    859. {
    860. c.Minutes[begin] = 1;
    861. if ((begin + interval) >= 60)
    862. break;
    863. begin += interval;
    864. }
    865. }
    866. else if (str.Contains(','))
    867. {
    868. for (int i = 0; i < str.Split(',').Length; i++)
    869. {
    870. c.Minutes[int.Parse(str.Split(',')[i])] = 1;
    871. }
    872. }
    873. else
    874. {
    875. c.Minutes[int.Parse(str)] = 1;
    876. }
    877. }
    878. private static void Hours(Cron c, string str)
    879. {
    880. if (str == "*")
    881. {
    882. for (int i = 0; i < 24; i++)
    883. {
    884. c.Hours[i] = 1;
    885. }
    886. }
    887. else if (str.Contains('-'))
    888. {
    889. int begin = int.Parse(str.Split('-')[0]);
    890. int end = int.Parse(str.Split('-')[1]);
    891. for (int i = begin; i <= end; i++)
    892. {
    893. c.Hours[i] = 1;
    894. }
    895. }
    896. else if (str.Contains('/'))
    897. {
    898. int begin = int.Parse(str.Split('/')[0]);
    899. int interval = int.Parse(str.Split('/')[1]);
    900. while (true)
    901. {
    902. c.Hours[begin] = 1;
    903. if ((begin + interval) >= 24)
    904. break;
    905. begin += interval;
    906. }
    907. }
    908. else if (str.Contains(','))
    909. {
    910. for (int i = 0; i < str.Split(',').Length; i++)
    911. {
    912. c.Hours[int.Parse(str.Split(',')[i])] = 1;
    913. }
    914. }
    915. else
    916. {
    917. c.Hours[int.Parse(str)] = 1;
    918. }
    919. }
    920. private static void Month(Cron c, string str)
    921. {
    922. if (str == "*")
    923. {
    924. for (int i = 0; i < 12; i++)
    925. {
    926. c.Month[i] = 1;
    927. }
    928. }
    929. else if (str.Contains('-'))
    930. {
    931. int begin = int.Parse(str.Split('-')[0]);
    932. int end = int.Parse(str.Split('-')[1]);
    933. for (int i = begin; i <= end; i++)
    934. {
    935. c.Month[i - 1] = 1;
    936. }
    937. }
    938. else if (str.Contains('/'))
    939. {
    940. int begin = int.Parse(str.Split('/')[0]);
    941. int interval = int.Parse(str.Split('/')[1]);
    942. while (true)
    943. {
    944. c.Month[begin - 1] = 1;
    945. if ((begin + interval) >= 12)
    946. break;
    947. begin += interval;
    948. }
    949. }
    950. else if (str.Contains(','))
    951. {
    952. for (int i = 0; i < str.Split(',').Length; i++)
    953. {
    954. c.Month[int.Parse(str.Split(',')[i]) - 1] = 1;
    955. }
    956. }
    957. else
    958. {
    959. c.Month[int.Parse(str) - 1] = 1;
    960. }
    961. }
    962. private static void Year(Cron c, string str)
    963. {
    964. if (str == null || str == "*")
    965. {
    966. for (int i = 0; i < 80; i++)
    967. {
    968. c.Year[i] = 1;
    969. }
    970. }
    971. else if (str.Contains('-'))
    972. {
    973. int begin = int.Parse(str.Split('-')[0]);
    974. int end = int.Parse(str.Split('-')[1]);
    975. for (int i = begin - 2019; i <= end - 2019; i++)
    976. {
    977. c.Year[i] = 1;
    978. }
    979. }
    980. else
    981. {
    982. c.Year[int.Parse(str) - 2019] = 1;
    983. }
    984. }
    985. private static void Days(Cron c, string str, int len, DateTime now)
    986. {
    987. for (int i = 0; i < 7; i++)
    988. {
    989. c.Weeks[i] = 1;
    990. }
    991. if (str == "*" || str == "?")
    992. {
    993. for (int i = 0; i < len; i++)
    994. {
    995. c.Days[i] = 1;
    996. }
    997. }
    998. else if (str.Contains('-'))
    999. {
    1000. int begin = int.Parse(str.Split('-')[0]);
    1001. int end = int.Parse(str.Split('-')[1]);
    1002. for (int i = begin; i <= end; i++)
    1003. {
    1004. c.Days[i - 1] = 1;
    1005. }
    1006. }
    1007. else if (str.Contains('/'))
    1008. {
    1009. int begin = int.Parse(str.Split('/')[0]);
    1010. int interval = int.Parse(str.Split('/')[1]);
    1011. while (true)
    1012. {
    1013. c.Days[begin - 1] = 1;
    1014. if ((begin + interval) > len)
    1015. break;
    1016. begin += interval;
    1017. }
    1018. }
    1019. else if (str.Contains(','))
    1020. {
    1021. for (int i = 0; i < str.Split(',').Length; i++)
    1022. {
    1023. c.Days[int.Parse(str.Split(',')[i]) - 1] = 1;
    1024. }
    1025. }
    1026. else if (str.Contains('L'))
    1027. {
    1028. int i = str.Replace("L", "") == "" ? 0 : int.Parse(str.Replace("L", ""));
    1029. c.Days[len - 1 - i] = 1;
    1030. }
    1031. else if (str.Contains('W'))
    1032. {
    1033. c.Days[len - 1] = 1;
    1034. }
    1035. else
    1036. {
    1037. c.Days[int.Parse(str) - 1] = 1;
    1038. }
    1039. }
    1040. private static void Weeks(Cron c, string str, int len, DateTime now)
    1041. {
    1042. if (str == "*" || str == "?")
    1043. {
    1044. for (int i = 0; i < 7; i++)
    1045. {
    1046. c.Weeks[i] = 1;
    1047. }
    1048. }
    1049. else if (str.Contains('-'))
    1050. {
    1051. int begin = int.Parse(str.Split('-')[0]);
    1052. int end = int.Parse(str.Split('-')[1]);
    1053. for (int i = begin; i <= end; i++)
    1054. {
    1055. c.Weeks[i - 1] = 1;
    1056. }
    1057. }
    1058. else if (str.Contains(','))
    1059. {
    1060. for (int i = 0; i < str.Split(',').Length; i++)
    1061. {
    1062. string num = str.Split(',')[i];
    1063. //if (num == "0")
    1064. //{
    1065. // num = "1";
    1066. //}
    1067. c.Weeks[int.Parse(num) - 1] = 1;
    1068. }
    1069. }
    1070. else if (str.Contains('L'))
    1071. {
    1072. int i = str.Replace("L", "") == "" ? 0 : int.Parse(str.Replace("L", ""));
    1073. if (i == 0)
    1074. {
    1075. c.Weeks[6] = 1;
    1076. }
    1077. else
    1078. {
    1079. c.Weeks[i - 1] = 1;
    1080. c.Days[GetLastWeek(i, now) - 1] = 1;
    1081. return;
    1082. }
    1083. }
    1084. else if (str.Contains('#'))
    1085. {
    1086. int i = int.Parse(str.Split('#')[0]);
    1087. int j = int.Parse(str.Split('#')[1]);
    1088. c.Weeks[i - 1] = 1;
    1089. c.Days[GetWeek(i - 1, j, now)] = 1;
    1090. return;
    1091. }
    1092. else
    1093. {
    1094. c.Weeks[int.Parse(str) - 1] = 1;
    1095. }
    1096. //week中初始化day,则说明day没要求
    1097. for (int i = 0; i < len; i++)
    1098. {
    1099. c.Days[i] = 1;
    1100. }
    1101. }
    1102. /// <summary>
    1103. /// 中文月份转化为数字
    1104. /// </summary>
    1105. /// <param name="chineseMonth"></param>
    1106. /// <returns></returns>
    1107. public static string GetMonthByChinese(string chineseMonth)
    1108. {
    1109. string[] monthArr = chineseMonth.Split(',');
    1110. string monthNum = string.Empty;
    1111. foreach (var item in monthArr)
    1112. {
    1113. switch (item)
    1114. {
    1115. case "一月": monthNum = monthNum + "," + 1; break;
    1116. case "二月": monthNum = monthNum + "," + 2; break;
    1117. case "三月": monthNum = monthNum + "," + 3; break;
    1118. case "四月": monthNum = monthNum + "," + 4; break;
    1119. case "五月": monthNum = monthNum + "," + 5; break;
    1120. case "六月": monthNum = monthNum + "," + 6; break;
    1121. case "七月": monthNum = monthNum + "," + 7; break;
    1122. case "八月": monthNum = monthNum + "," + 8; break;
    1123. case "九月": monthNum = monthNum + "," + 9; break;
    1124. case "十月": monthNum = monthNum + "," + 10; break;
    1125. case "十一月": monthNum = monthNum + "," + 11; break;
    1126. case "十二月": monthNum = monthNum + "," + 12; break;
    1127. default: monthNum = "A"; break;
    1128. }
    1129. }
    1130. return monthNum.Trim(',');
    1131. }
    1132. public static string GetWeekByChinese(string chineseWeek)
    1133. {
    1134. string[] weekArr = chineseWeek.Split(',');
    1135. string weekNum = string.Empty;
    1136. foreach (var item in weekArr)
    1137. {
    1138. switch (item)
    1139. {
    1140. case "星期一": weekNum = weekNum + "," + 1; break;
    1141. case "星期二": weekNum = weekNum + "," + 2; break;
    1142. case "星期三": weekNum = weekNum + "," + 3; break;
    1143. case "星期四": weekNum = weekNum + "," + 4; break;
    1144. case "星期五": weekNum = weekNum + "," + 5; break;
    1145. case "星期六": weekNum = weekNum + "," + 6; break;
    1146. case "星期日": weekNum = weekNum + "," + 7; break;
    1147. }
    1148. }
    1149. return weekNum.Trim(',');
    1150. }
    1151. #endregion
    1152. /// <summary>
    1153. /// 是否执行一次
    1154. /// </summary>
    1155. /// <param name="cron"></param>
    1156. /// <returns></returns>
    1157. public static bool IsOrNoOne(string cron)
    1158. {
    1159. if (cron.Contains('-') || cron.Contains(',') || cron.Contains('/') || cron.Contains('*'))
    1160. {
    1161. return false;
    1162. }
    1163. else
    1164. {
    1165. return true;
    1166. }
    1167. }
    1168. /// <summary>
    1169. /// 获取最后一个星期几的day
    1170. /// </summary>
    1171. /// <param name="i">星期几</param>
    1172. /// <param name="now"></param>
    1173. /// <returns></returns>
    1174. public static int GetLastWeek(int i, DateTime now)
    1175. {
    1176. DateTime d = now.AddDays(1 - now.Day).Date.AddMonths(1).AddSeconds(-1);
    1177. int DayOfWeek = ((((int)d.DayOfWeek) + 6) % 7) + 1;
    1178. int a = DayOfWeek >= i ? DayOfWeek - i : 7 + DayOfWeek - i;
    1179. return DateTime.DaysInMonth(now.Year, now.Month) - a;
    1180. }
    1181. /// <summary>
    1182. /// 获取当月第几个星期几的day
    1183. /// </summary>
    1184. /// <param name="i">星期几</param>
    1185. /// <param name="j">第几周</param>
    1186. /// <param name="now"></param>
    1187. /// <returns></returns>
    1188. public static int GetWeek(int i, int j, DateTime now)
    1189. {
    1190. int day = 0;
    1191. DateTime d = new DateTime(now.Year, now.Month, 1);
    1192. int DayOfWeek = ((((int)d.DayOfWeek) + 6) % 7) + 1;
    1193. if (i >= DayOfWeek)
    1194. {
    1195. day = (7 - DayOfWeek + 1) + 7 * (j - 2) + i;
    1196. }
    1197. else
    1198. {
    1199. day = (7 - DayOfWeek + 1) + 7 * (j - 1) + i;
    1200. }
    1201. return day;
    1202. }
    1203. }
    1204. }