No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Solar.cs 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using Lunar.Util;
  5. // ReSharper disable MemberCanBePrivate.Global
  6. // ReSharper disable IdentifierTypo
  7. namespace Lunar
  8. {
  9. /// <summary>
  10. /// 阳历日期
  11. /// </summary>
  12. public class Solar
  13. {
  14. /// <summary>
  15. /// 2000年儒略日数(2000-1-1 12:00:00 UTC)
  16. /// </summary>
  17. public const double J2000 = 2451545;
  18. /// <summary>
  19. /// 年
  20. /// </summary>
  21. public int Year { get; }
  22. /// <summary>
  23. /// 月
  24. /// </summary>
  25. public int Month { get; }
  26. /// <summary>
  27. /// 日
  28. /// </summary>
  29. public int Day { get; }
  30. /// <summary>
  31. /// 时
  32. /// </summary>
  33. public int Hour { get; }
  34. /// <summary>
  35. /// 分
  36. /// </summary>
  37. public int Minute { get; }
  38. /// <summary>
  39. /// 秒
  40. /// </summary>
  41. public int Second { get; }
  42. /// <summary>
  43. /// 默认使用当前日期初始化
  44. /// </summary>
  45. public Solar(): this(DateTime.Now)
  46. {
  47. }
  48. /// <summary>
  49. /// 通过年月日时分初始化
  50. /// </summary>
  51. /// <param name="year">年</param>
  52. /// <param name="month">月,1到12</param>
  53. /// <param name="day">日,1到31</param>
  54. /// <param name="hour">小时,0到23</param>
  55. /// <param name="minute">分钟,0到59</param>
  56. /// <param name="second">秒钟,0到59</param>
  57. public Solar(int year, int month, int day, int hour = 0, int minute = 0, int second = 0)
  58. {
  59. if (1582 == year && 10 == month)
  60. {
  61. if (day > 4 && day < 15)
  62. {
  63. throw new ArgumentException($"wrong solar year {year} month {month} day {day}");
  64. }
  65. }
  66. if (month < 1 || month > 12)
  67. {
  68. throw new ArgumentException($"wrong month {month}");
  69. }
  70. if (day < 1 || day > 31)
  71. {
  72. throw new ArgumentException($"wrong day {day}");
  73. }
  74. if (hour < 0 || hour > 23)
  75. {
  76. throw new ArgumentException($"wrong hour {hour}");
  77. }
  78. if (minute < 0 || minute > 59)
  79. {
  80. throw new ArgumentException($"wrong minute {minute}");
  81. }
  82. if (second < 0 || second > 59)
  83. {
  84. throw new ArgumentException($"wrong second {second}");
  85. }
  86. Year = year;
  87. Month = month;
  88. Day = day;
  89. Hour = hour;
  90. Minute = minute;
  91. Second = second;
  92. }
  93. /// <summary>
  94. /// 通过日期初始化
  95. /// </summary>
  96. /// <param name="date">日期</param>
  97. public Solar(DateTime date): this(date.Year, date.Month, date.Day, date.Hour, date.Minute,date.Second)
  98. {
  99. }
  100. /// <summary>
  101. /// 通过儒略日初始化
  102. /// </summary>
  103. /// <param name="julianDay">儒略日</param>
  104. public Solar(double julianDay)
  105. {
  106. var d = (int)(julianDay + 0.5);
  107. var f = julianDay + 0.5 - d;
  108. if (d >= 2299161)
  109. {
  110. var c = (int)((d - 1867216.25) / 36524.25);
  111. d += 1 + c - (int)(c * 1D / 4);
  112. }
  113. d += 1524;
  114. var year = (int)((d - 122.1) / 365.25);
  115. d -= (int)(365.25 * year);
  116. var month = (int)(d * 1D / 30.601);
  117. d -= (int)(30.601 * month);
  118. var day = d;
  119. if (month > 13)
  120. {
  121. month -= 13;
  122. year -= 4715;
  123. }
  124. else
  125. {
  126. month -= 1;
  127. year -= 4716;
  128. }
  129. f *= 24;
  130. var hour = (int)f;
  131. f -= hour;
  132. f *= 60;
  133. var minute = (int)f;
  134. f -= minute;
  135. f *= 60;
  136. var second = (int)Math.Round(f);
  137. if (second > 59)
  138. {
  139. second -= 60;
  140. minute++;
  141. }
  142. if (minute > 59)
  143. {
  144. minute -= 60;
  145. hour++;
  146. }
  147. if (hour > 23)
  148. {
  149. hour -= 24;
  150. day += 1;
  151. }
  152. Year = year;
  153. Month = month;
  154. Day = day;
  155. Hour = hour;
  156. Minute = minute;
  157. Second = second;
  158. }
  159. /// <summary>
  160. /// 通过指定年月日时分获取阳历
  161. /// </summary>
  162. /// <param name="year">年</param>
  163. /// <param name="month">月,1到12</param>
  164. /// <param name="day">日,1到31</param>
  165. /// <param name="hour">小时,0到23</param>
  166. /// <param name="minute">分钟,0到59</param>
  167. /// <param name="second">秒钟,0到59</param>
  168. /// <returns>阳历</returns>
  169. public static Solar FromYmdHms(int year, int month, int day, int hour = 0, int minute = 0,int second = 0)
  170. {
  171. return new Solar(year, month, day, hour, minute,second);
  172. }
  173. /// <summary>
  174. /// 通过指定日期获取阳历
  175. /// </summary>
  176. /// <param name="date">日期</param>
  177. /// <returns>阳历</returns>
  178. public static Solar FromDate(DateTime date)
  179. {
  180. return new Solar(date);
  181. }
  182. /// <summary>
  183. /// 通过指定儒略日获取阳历
  184. /// </summary>
  185. /// <param name="julianDay">儒略日</param>
  186. /// <returns>阳历</returns>
  187. public static Solar FromJulianDay(double julianDay)
  188. {
  189. return new Solar(julianDay);
  190. }
  191. /// <summary>
  192. /// 通过八字获取阳历列表
  193. /// </summary>
  194. /// <param name="yearGanZhi">年柱</param>
  195. /// <param name="monthGanZhi">月柱</param>
  196. /// <param name="dayGanZhi">日柱</param>
  197. /// <param name="timeGanZhi">时柱</param>
  198. /// <param name="sect">流派,2晚子时日柱按当天,1晚子时日柱按明天</param>
  199. /// <param name="baseYear">起始年</param>
  200. /// <returns>符合的阳历列表</returns>
  201. public static List<Solar> FromBaZi(string yearGanZhi, string monthGanZhi, string dayGanZhi, string timeGanZhi,
  202. int sect = 2, int baseYear = 1900)
  203. {
  204. sect = (1 == sect) ? 1 : 2;
  205. var l = new List<Solar>();
  206. // 月地支距寅月的偏移值
  207. var m = LunarUtil.find(monthGanZhi.Substring(1), LunarUtil.ZHI, -1) - 2;
  208. if (m < 0)
  209. {
  210. m += 12;
  211. }
  212. // 月天干要一致
  213. if (((LunarUtil.find(yearGanZhi.Substring(0, 1), LunarUtil.GAN, -1) + 1) * 2 + m) % 10 !=
  214. LunarUtil.find(monthGanZhi.Substring(0, 1), LunarUtil.GAN, -1))
  215. {
  216. return l;
  217. }
  218. // 1年的立春是辛酉,序号57
  219. var y = LunarUtil.GetJiaZiIndex(yearGanZhi) - 57;
  220. if (y < 0)
  221. {
  222. y += 60;
  223. }
  224. y++;
  225. // 节令偏移值
  226. m *= 2;
  227. // 时辰地支转时刻,子时按零点算
  228. var h = LunarUtil.find(timeGanZhi.Substring(1), LunarUtil.ZHI, -1) * 2;
  229. int[] hours = { h };
  230. if (0 == h && 2 == sect)
  231. {
  232. hours = new [] { 0, 23 };
  233. }
  234. var startYear = baseYear - 1;
  235. // 结束年
  236. var endYear = DateTime.Now.Year;
  237. while (y <= endYear)
  238. {
  239. if (y >= startYear)
  240. {
  241. // 立春为寅月的开始
  242. var solarTime = Lunar.FromYmdHms(y, 1, 1).JieQiTable[Lunar.JIE_QI_IN_USE[4 + m]];
  243. // 节令推移,年干支和月干支就都匹配上了
  244. if (solarTime.Year >= baseYear)
  245. {
  246. // 日干支和节令干支的偏移值
  247. var d = LunarUtil.GetJiaZiIndex(dayGanZhi) - LunarUtil.GetJiaZiIndex(solarTime.Lunar.DayInGanZhiExact2);
  248. if (d < 0)
  249. {
  250. d += 60;
  251. }
  252. if (d > 0)
  253. {
  254. // 从节令推移天数
  255. solarTime = solarTime.Next(d);
  256. }
  257. foreach (var hour in hours)
  258. {
  259. var mi = 0;
  260. var s = 0;
  261. if (d == 0 && hour == solarTime.Hour)
  262. {
  263. // 如果正好是节令当天,且小时和节令的小时数相等的极端情况,把分钟和秒钟带上
  264. mi = solarTime.Minute;
  265. s = solarTime.Second;
  266. }
  267. // 验证一下
  268. var solar = FromYmdHms(solarTime.Year, solarTime.Month, solarTime.Day, hour, mi, s);
  269. var lunar = solar.Lunar;
  270. var dgz = (2 == sect) ? lunar.DayInGanZhiExact2 : lunar.DayInGanZhiExact;
  271. if (lunar.YearInGanZhiExact.Equals(yearGanZhi) &&
  272. lunar.MonthInGanZhiExact.Equals(monthGanZhi) && dgz.Equals(dayGanZhi) &&
  273. lunar.TimeInGanZhi.Equals(timeGanZhi))
  274. {
  275. l.Add(solar);
  276. }
  277. }
  278. }
  279. }
  280. y += 60;
  281. }
  282. return l;
  283. }
  284. /// <summary>
  285. /// 是否闰年
  286. /// </summary>
  287. public bool LeapYear => SolarUtil.IsLeapYear(Year);
  288. /// <summary>
  289. /// 星期,0代表周日,1代表周一
  290. /// </summary>
  291. public int Week => ((int)(JulianDay + 0.5) + 7000001) % 7;
  292. /// <summary>
  293. /// 星期的中文:日一二三四五六
  294. /// </summary>
  295. public string WeekInChinese => SolarUtil.WEEK[Week];
  296. /// <summary>
  297. /// 星座
  298. /// </summary>
  299. public string XingZuo
  300. {
  301. get
  302. {
  303. var index = 11;
  304. var y = Month * 100 + Day;
  305. if (y >= 321 && y <= 419) {
  306. index = 0;
  307. } else if (y >= 420 && y <= 520) {
  308. index = 1;
  309. } else if (y >= 521 && y <= 621) {
  310. index = 2;
  311. } else if (y >= 622 && y <= 722) {
  312. index = 3;
  313. } else if (y >= 723 && y <= 822) {
  314. index = 4;
  315. } else if (y >= 823 && y <= 922) {
  316. index = 5;
  317. } else if (y >= 923 && y <= 1023) {
  318. index = 6;
  319. } else if (y >= 1024 && y <= 1122) {
  320. index = 7;
  321. } else if (y >= 1123 && y <= 1221) {
  322. index = 8;
  323. } else if (y >= 1222 || y <= 119) {
  324. index = 9;
  325. } else if (y <= 218) {
  326. index = 10;
  327. }
  328. return SolarUtil.XING_ZUO[index];
  329. }
  330. }
  331. /// <summary>
  332. /// 节日,有可能一天会有多个节日
  333. /// </summary>
  334. public List<string> Festivals
  335. {
  336. get
  337. {
  338. var l = new List<string>();
  339. //获取几月几日对应的节日
  340. try
  341. {
  342. l.Add(SolarUtil.FESTIVAL[Month + "-" + Day]);
  343. }
  344. catch
  345. {
  346. // ignored
  347. }
  348. //计算几月第几个星期几对应的节日
  349. var weeks = (int)Math.Ceiling(Day / 7D);
  350. //星期几,0代表星期天
  351. try
  352. {
  353. l.Add(SolarUtil.WEEK_FESTIVAL[Month + "-" + weeks + "-" + Week]);
  354. }
  355. catch
  356. {
  357. // ignored
  358. }
  359. if (Day + 7 <= SolarUtil.GetDaysOfMonth(Year, Month)) return l;
  360. try
  361. {
  362. l.Add(SolarUtil.WEEK_FESTIVAL[Month + "-0-" + Week]);
  363. }
  364. catch
  365. {
  366. // ignored
  367. }
  368. return l;
  369. }
  370. }
  371. /// <summary>
  372. /// 非正式节日
  373. /// </summary>
  374. public List<string> OtherFestivals
  375. {
  376. get
  377. {
  378. var l = new List<string>();
  379. try
  380. {
  381. var fs = SolarUtil.OTHER_FESTIVAL[Month + "-" + Day];
  382. l.AddRange(fs);
  383. }
  384. catch
  385. {
  386. // ignored
  387. }
  388. return l;
  389. }
  390. }
  391. /// <summary>
  392. /// 阴历
  393. /// </summary>
  394. public Lunar Lunar => new Lunar(this);
  395. /// <summary>
  396. /// 儒略日
  397. /// </summary>
  398. public double JulianDay
  399. {
  400. get
  401. {
  402. var y = Year;
  403. var m = Month;
  404. var d = Day + ((Second * 1D / 60 + Minute) / 60 + Hour) / 24;
  405. var n = 0;
  406. var g = y * 372 + m * 31 + (int)d >= 588829;
  407. if (m <= 2)
  408. {
  409. m += 12;
  410. y--;
  411. }
  412. if (g)
  413. {
  414. n = (int)(y * 1D / 100);
  415. n = 2 - n + (int)(n * 1D / 4);
  416. }
  417. return (int)(365.25 * (y + 4716)) + (int)(30.6001 * (m + 1)) + d + n - 1524.5;
  418. }
  419. }
  420. /// <inheritdoc />
  421. public override string ToString()
  422. {
  423. return Ymd;
  424. }
  425. /// <summary>
  426. /// yyyy-MM-dd
  427. /// </summary>
  428. public string Ymd
  429. {
  430. get
  431. {
  432. var y = Year + "";
  433. while (y.Length < 4)
  434. {
  435. y = "0" + y;
  436. }
  437. return y + "-" + (Month < 10 ? "0" : "") + Month + "-" + (Day < 10 ? "0" : "") + Day;
  438. }
  439. }
  440. /// <summary>
  441. /// yyyy-MM-dd HH:mm:ss
  442. /// </summary>
  443. public string YmdHms => Ymd + " " + (Hour < 10 ? "0" : "") + Hour + ":" + (Minute < 10 ? "0" : "") + Minute + ":" + (Second < 10 ? "0" : "") + Second;
  444. /// <summary>
  445. /// 完整字符串输出
  446. /// </summary>
  447. public string FullString
  448. {
  449. get
  450. {
  451. var s = new StringBuilder();
  452. s.Append(YmdHms);
  453. if (LeapYear)
  454. {
  455. s.Append(' ');
  456. s.Append("闰年");
  457. }
  458. s.Append(' ');
  459. s.Append("星期");
  460. s.Append(WeekInChinese);
  461. s.Append(' ');
  462. s.Append(XingZuo);
  463. s.Append('座');
  464. return s.ToString();
  465. }
  466. }
  467. /// <summary>
  468. /// 阳历日期相减,获得相差天数
  469. /// </summary>
  470. /// <param name="solar">阳历</param>
  471. /// <returns>天数</returns>
  472. public int Subtract(Solar solar)
  473. {
  474. return SolarUtil.GetDaysBetween(solar.Year, solar.Month, solar.Day, Year, Month, Day);
  475. }
  476. /// <summary>
  477. /// 阳历日期相减,获得相差分钟数
  478. /// </summary>
  479. /// <param name="solar">阳历</param>
  480. /// <returns>分钟数</returns>
  481. public int SubtractMinute(Solar solar)
  482. {
  483. var days = Subtract(solar);
  484. var cm = Hour * 60 + Minute;
  485. var sm = solar.Hour * 60 + solar.Minute;
  486. var m = cm - sm;
  487. if (m < 0)
  488. {
  489. m += 1440;
  490. days--;
  491. }
  492. m += days * 1440;
  493. return m;
  494. }
  495. /// <summary>
  496. /// 是否在指定日期之后
  497. /// </summary>
  498. /// <param name="solar">阳历</param>
  499. /// <returns>true/false</returns>
  500. public bool IsAfter(Solar solar)
  501. {
  502. if (Year > solar.Year)
  503. {
  504. return true;
  505. }
  506. if (Year < solar.Year)
  507. {
  508. return false;
  509. }
  510. if (Month > solar.Month)
  511. {
  512. return true;
  513. }
  514. if (Month < solar.Month)
  515. {
  516. return false;
  517. }
  518. if (Day > solar.Day) {
  519. return true;
  520. }
  521. if (Day < solar.Day)
  522. {
  523. return false;
  524. }
  525. if (Hour > solar.Hour)
  526. {
  527. return true;
  528. }
  529. if (Hour < solar.Hour)
  530. {
  531. return false;
  532. }
  533. if (Minute > solar.Minute)
  534. {
  535. return true;
  536. }
  537. if (Minute < solar.Minute)
  538. {
  539. return false;
  540. }
  541. return Second > solar.Second;
  542. }
  543. /// <summary>
  544. /// 是否在指定日期之前
  545. /// </summary>
  546. /// <param name="solar">阳历</param>
  547. /// <returns>true/false</returns>
  548. public bool IsBefore(Solar solar)
  549. {
  550. if (Year > solar.Year)
  551. {
  552. return false;
  553. }
  554. if (Year < solar.Year)
  555. {
  556. return true;
  557. }
  558. if (Month > solar.Month)
  559. {
  560. return false;
  561. }
  562. if (Month < solar.Month)
  563. {
  564. return true;
  565. }
  566. if (Day > solar.Day)
  567. {
  568. return false;
  569. }
  570. if (Day < solar.Day)
  571. {
  572. return true;
  573. }
  574. if (Hour > solar.Hour)
  575. {
  576. return false;
  577. }
  578. if (Hour < solar.Hour)
  579. {
  580. return true;
  581. }
  582. if (Minute > solar.Minute)
  583. {
  584. return false;
  585. }
  586. if (Minute < solar.Minute)
  587. {
  588. return true;
  589. }
  590. return Second < solar.Second;
  591. }
  592. /// <summary>
  593. /// 年推移
  594. /// </summary>
  595. /// <param name="years">年数</param>
  596. /// <returns>阳历</returns>
  597. public Solar NextYear(int years)
  598. {
  599. var y = Year + years;
  600. var m = Month;
  601. var d = Day;
  602. if (1582 == y && 10 == m)
  603. {
  604. if (d > 4 && d < 15)
  605. {
  606. d += 10;
  607. }
  608. }
  609. else if (2 == m)
  610. {
  611. if (d > 28)
  612. {
  613. if (!SolarUtil.IsLeapYear(y))
  614. {
  615. d = 28;
  616. }
  617. }
  618. }
  619. return new Solar(y, m, d, Hour, Minute, Second);
  620. }
  621. /// <summary>
  622. /// 月推移
  623. /// </summary>
  624. /// <param name="months">月数</param>
  625. /// <returns>阳历</returns>
  626. public Solar NextMonth(int months)
  627. {
  628. var month = SolarMonth.FromYm(Year, Month).Next(months);
  629. var y = month.Year;
  630. var m = month.Month;
  631. var d = Day;
  632. if (1582 == y && 10 == m)
  633. {
  634. if (d > 4 && d < 15)
  635. {
  636. d += 10;
  637. }
  638. }
  639. else
  640. {
  641. var maxDay = SolarUtil.GetDaysOfMonth(y, m);
  642. if (d > maxDay)
  643. {
  644. d = maxDay;
  645. }
  646. }
  647. return new Solar(y, m, d, Hour, Minute, Second);
  648. }
  649. /// <summary>
  650. /// 日推移
  651. /// </summary>
  652. /// <param name="days">天数</param>
  653. /// <returns>阳历</returns>
  654. public Solar NextDay(int days)
  655. {
  656. var y = Year;
  657. var m = Month;
  658. var d = Day;
  659. if (1582 == y && 10 == m)
  660. {
  661. if (d > 4)
  662. {
  663. d -= 10;
  664. }
  665. }
  666. if (days > 0)
  667. {
  668. d += days;
  669. var daysInMonth = SolarUtil.GetDaysOfMonth(y, m);
  670. while (d > daysInMonth) {
  671. d -= daysInMonth;
  672. m++;
  673. if (m > 12) {
  674. m = 1;
  675. y++;
  676. }
  677. daysInMonth = SolarUtil.GetDaysOfMonth(y, m);
  678. }
  679. } else if (days < 0)
  680. {
  681. while (d + days <= 0)
  682. {
  683. m--;
  684. if (m < 1) {
  685. m = 12;
  686. y--;
  687. }
  688. d += SolarUtil.GetDaysOfMonth(y, m);
  689. }
  690. d += days;
  691. }
  692. if (1582 == y && 10 == m)
  693. {
  694. if (d > 4) {
  695. d += 10;
  696. }
  697. }
  698. return new Solar(y, m, d, Hour, Minute, Second);
  699. }
  700. /// <summary>
  701. /// 获取往后推几天的阳历日期,如果要往前推,则天数用负数
  702. /// </summary>
  703. /// <param name="days">天数</param>
  704. /// <param name="onlyWorkday">是否仅工作日</param>
  705. /// <returns>阳历日期</returns>
  706. public Solar Next(int days, bool onlyWorkday = false)
  707. {
  708. if(!onlyWorkday)
  709. {
  710. return NextDay(days);
  711. }
  712. var solar = new Solar(Year, Month, Day, Hour, Minute, Second);
  713. if (days != 0)
  714. {
  715. var rest = Math.Abs(days);
  716. var add = days < 0 ? -1 : 1;
  717. while (rest > 0)
  718. {
  719. solar = solar.Next(add);
  720. var work = true;
  721. var holiday = HolidayUtil.GetHoliday(solar.Year, solar.Month, solar.Day);
  722. if (null == holiday)
  723. {
  724. var week = solar.Week;
  725. if (0 == week || 6 == week) {
  726. work = false;
  727. }
  728. } else
  729. {
  730. work = holiday.Work;
  731. }
  732. if (work)
  733. {
  734. rest -= 1;
  735. }
  736. }
  737. }
  738. return solar;
  739. }
  740. /// <summary>
  741. /// 小时推移
  742. /// </summary>
  743. /// <param name="hours">小时数</param>
  744. /// <returns>阳历</returns>
  745. public Solar NextHour(int hours)
  746. {
  747. var h = Hour + hours;
  748. var n = h < 0 ? -1 : 1;
  749. var hour = Math.Abs(h);
  750. var days = hour / 24 * n;
  751. hour = (hour % 24) * n;
  752. if (hour < 0)
  753. {
  754. hour += 24;
  755. days--;
  756. }
  757. var solar = Next(days);
  758. return new Solar(solar.Year, solar.Month, solar.Day, hour, solar.Minute, solar.Second);
  759. }
  760. /// <summary>
  761. /// 获取薪资比例(感谢 https://gitee.com/smr1987)
  762. /// </summary>
  763. /// <returns>薪资比例:1/2/3</returns>
  764. public int GetSalaryRate()
  765. {
  766. switch (Month)
  767. {
  768. // 元旦节
  769. case 1 when Day == 1:
  770. // 劳动节
  771. case 5 when Day == 1:
  772. // 国庆
  773. case 10 when Day >= 1 && Day <= 3:
  774. return 3;
  775. }
  776. var lunarMonth = Lunar.Month;
  777. var lunarDay = Lunar.Day;
  778. switch (lunarMonth)
  779. {
  780. // 春节
  781. case 1 when lunarDay >= 1 && lunarDay <= 3:
  782. // 端午
  783. case 5 when lunarDay == 5:
  784. // 中秋
  785. case 8 when lunarDay == 15:
  786. return 3;
  787. }
  788. // 清明
  789. if ("清明".Equals(Lunar.JieQi)) {
  790. return 3;
  791. }
  792. var holiday = HolidayUtil.GetHoliday(Year, Month, Day);
  793. if (null != holiday) {
  794. // 法定假日非上班
  795. if (!holiday.Work) {
  796. return 2;
  797. }
  798. } else {
  799. // 周末
  800. var week = Week;
  801. if (week == 6 || week == 0) {
  802. return 2;
  803. }
  804. }
  805. // 工作日
  806. return 1;
  807. }
  808. }
  809. }