DateTimeHelper.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. using System;
  2. using System.Diagnostics;
  3. using System.Globalization;
  4. using System.Runtime.InteropServices;
  5. namespace Masuit.Tools.DateTimeExt
  6. {
  7. /// <summary>
  8. /// 日期操作工具类
  9. /// </summary>
  10. public static class DateUtil
  11. {
  12. /// <summary>
  13. /// 获取某一年有多少周
  14. /// </summary>
  15. /// <param name="_"></param>
  16. /// <param name="year">年份</param>
  17. /// <returns>该年周数</returns>
  18. public static int GetWeekAmount(this DateTime _, int year)
  19. {
  20. var end = new DateTime(year, 12, 31); //该年最后一天
  21. var gc = new GregorianCalendar();
  22. return gc.GetWeekOfYear(end, CalendarWeekRule.FirstDay, DayOfWeek.Monday); //该年星期数
  23. }
  24. /// <summary>
  25. /// 返回年度第几个星期 默认星期日是第一天
  26. /// </summary>
  27. /// <param name="date">时间</param>
  28. /// <returns>第几周</returns>
  29. public static int WeekOfYear(this in DateTime date)
  30. {
  31. var gc = new GregorianCalendar();
  32. return gc.GetWeekOfYear(date, CalendarWeekRule.FirstDay, DayOfWeek.Sunday);
  33. }
  34. /// <summary>
  35. /// 返回年度第几个星期
  36. /// </summary>
  37. /// <param name="date">时间</param>
  38. /// <param name="week">一周的开始日期</param>
  39. /// <returns>第几周</returns>
  40. public static int WeekOfYear(this in DateTime date, DayOfWeek week)
  41. {
  42. var gc = new GregorianCalendar();
  43. return gc.GetWeekOfYear(date, CalendarWeekRule.FirstDay, week);
  44. }
  45. /// <summary>
  46. /// 得到一年中的某周的起始日和截止日
  47. /// 年 nYear
  48. /// 周数 nNumWeek
  49. /// 周始 out dtWeekStart
  50. /// 周终 out dtWeekeEnd
  51. /// </summary>
  52. /// <param name="_"></param>
  53. /// <param name="nYear">年份</param>
  54. /// <param name="nNumWeek">第几周</param>
  55. /// <param name="dtWeekStart">开始日期</param>
  56. /// <param name="dtWeekeEnd">结束日期</param>
  57. public static void GetWeekTime(this DateTime _, int nYear, int nNumWeek, out DateTime dtWeekStart, out DateTime dtWeekeEnd)
  58. {
  59. var dt = new DateTime(nYear, 1, 1);
  60. dt += new TimeSpan((nNumWeek - 1) * 7, 0, 0, 0);
  61. dtWeekStart = dt.AddDays(-(int)dt.DayOfWeek + (int)DayOfWeek.Monday);
  62. dtWeekeEnd = dt.AddDays((int)DayOfWeek.Saturday - (int)dt.DayOfWeek + 1);
  63. }
  64. /// <summary>
  65. /// 得到一年中的某周的起始日和截止日 周一到周五 工作日
  66. /// </summary>
  67. /// <param name="_"></param>
  68. /// <param name="nYear">年份</param>
  69. /// <param name="nNumWeek">第几周</param>
  70. /// <param name="dtWeekStart">开始日期</param>
  71. /// <param name="dtWeekeEnd">结束日期</param>
  72. public static void GetWeekWorkTime(this DateTime _, int nYear, int nNumWeek, out DateTime dtWeekStart, out DateTime dtWeekeEnd)
  73. {
  74. var dt = new DateTime(nYear, 1, 1);
  75. dt += new TimeSpan((nNumWeek - 1) * 7, 0, 0, 0);
  76. dtWeekStart = dt.AddDays(-(int)dt.DayOfWeek + (int)DayOfWeek.Monday);
  77. dtWeekeEnd = dt.AddDays((int)DayOfWeek.Saturday - (int)dt.DayOfWeek + 1).AddDays(-2);
  78. }
  79. #region P/Invoke 设置本地时间
  80. [DllImport("kernel32.dll")]
  81. private static extern bool SetLocalTime(ref SystemTime time);
  82. [StructLayout(LayoutKind.Sequential)]
  83. private struct SystemTime
  84. {
  85. public short year;
  86. public short month;
  87. public short dayOfWeek;
  88. public short day;
  89. public short hour;
  90. public short minute;
  91. public short second;
  92. public short milliseconds;
  93. }
  94. /// <summary>
  95. /// 设置本地计算机时间
  96. /// </summary>
  97. /// <param name="dt">DateTime对象</param>
  98. public static void SetLocalTime(this in DateTime dt)
  99. {
  100. SystemTime st;
  101. st.year = (short)dt.Year;
  102. st.month = (short)dt.Month;
  103. st.dayOfWeek = (short)dt.DayOfWeek;
  104. st.day = (short)dt.Day;
  105. st.hour = (short)dt.Hour;
  106. st.minute = (short)dt.Minute;
  107. st.second = (short)dt.Second;
  108. st.milliseconds = (short)dt.Millisecond;
  109. SetLocalTime(ref st);
  110. }
  111. #endregion
  112. /// <summary>
  113. /// 返回相对于当前时间的相对天数
  114. /// </summary>
  115. /// <param name="dt"></param>
  116. /// <param name="relativeday">相对天数</param>
  117. public static string GetDateTime(this in DateTime dt, int relativeday)
  118. {
  119. return dt.AddDays(relativeday).ToString("yyyy-MM-dd HH:mm:ss");
  120. }
  121. /// <summary>
  122. /// 返回标准时间格式string
  123. /// </summary>
  124. public static string GetDateTimeF(this in DateTime dt) => dt.ToString("yyyy-MM-dd HH:mm:ss:fffffff");
  125. /// <summary>
  126. /// 获取该时间相对于1970-01-01 00:00:00的秒数
  127. /// </summary>
  128. /// <param name="dt"></param>
  129. /// <returns></returns>
  130. public static double GetTotalSeconds(this in DateTime dt) => new DateTimeOffset(dt).ToUnixTimeSeconds();
  131. /// <summary>
  132. /// 获取该时间相对于1970-01-01 00:00:00的毫秒数
  133. /// </summary>
  134. /// <param name="dt"></param>
  135. /// <returns></returns>
  136. public static double GetTotalMilliseconds(this in DateTime dt) => new DateTimeOffset(dt).ToUnixTimeMilliseconds();
  137. /// <summary>
  138. /// 获取该时间相对于1970-01-01 00:00:00的微秒时间戳
  139. /// </summary>
  140. /// <param name="dt"></param>
  141. /// <returns></returns>
  142. public static long GetTotalMicroseconds(this in DateTime dt) => new DateTimeOffset(dt).Ticks / 10;
  143. /// <summary>
  144. /// 获取该时间相对于1970-01-01 00:00:00的纳秒时间戳
  145. /// </summary>
  146. /// <param name="dt"></param>
  147. /// <returns></returns>
  148. public static long GetTotalNanoseconds(this in DateTime dt) => new DateTimeOffset(dt).Ticks * 100 + Stopwatch.GetTimestamp() % 100;
  149. /// <summary>
  150. /// 获取该时间相对于1970-01-01 00:00:00的分钟数
  151. /// </summary>
  152. /// <param name="dt"></param>
  153. /// <returns></returns>
  154. public static double GetTotalMinutes(this in DateTime dt) => new DateTimeOffset(dt).Offset.TotalMinutes;
  155. /// <summary>
  156. /// 获取该时间相对于1970-01-01 00:00:00的小时数
  157. /// </summary>
  158. /// <param name="dt"></param>
  159. /// <returns></returns>
  160. public static double GetTotalHours(this in DateTime dt) => new DateTimeOffset(dt).Offset.TotalHours;
  161. /// <summary>
  162. /// 获取该时间相对于1970-01-01 00:00:00的天数
  163. /// </summary>
  164. /// <param name="dt"></param>
  165. /// <returns></returns>
  166. public static double GetTotalDays(this in DateTime dt) => new DateTimeOffset(dt).Offset.TotalDays;
  167. /// <summary>
  168. /// 返回本年有多少天
  169. /// </summary>
  170. /// <param name="_"></param>
  171. /// <param name="iYear">年份</param>
  172. /// <returns>本年的天数</returns>
  173. public static int GetDaysOfYear(this DateTime _, int iYear)
  174. {
  175. return IsRuYear(iYear) ? 366 : 365;
  176. }
  177. /// <summary>本年有多少天</summary>
  178. /// <param name="dt">日期</param>
  179. /// <returns>本天在当年的天数</returns>
  180. public static int GetDaysOfYear(this in DateTime dt)
  181. {
  182. //取得传入参数的年份部分,用来判断是否是闰年
  183. int n = dt.Year;
  184. return IsRuYear(n) ? 366 : 365;
  185. }
  186. /// <summary>本月有多少天</summary>
  187. /// <param name="_"></param>
  188. /// <param name="iYear">年</param>
  189. /// <param name="month">月</param>
  190. /// <returns>天数</returns>
  191. public static int GetDaysOfMonth(this DateTime _, int iYear, int month)
  192. {
  193. return month switch
  194. {
  195. 1 => 31,
  196. 2 => (IsRuYear(iYear) ? 29 : 28),
  197. 3 => 31,
  198. 4 => 30,
  199. 5 => 31,
  200. 6 => 30,
  201. 7 => 31,
  202. 8 => 31,
  203. 9 => 30,
  204. 10 => 31,
  205. 11 => 30,
  206. 12 => 31,
  207. _ => 0
  208. };
  209. }
  210. /// <summary>本月有多少天</summary>
  211. /// <param name="dt">日期</param>
  212. /// <returns>天数</returns>
  213. public static int GetDaysOfMonth(this in DateTime dt)
  214. {
  215. //--利用年月信息,得到当前月的天数信息。
  216. return dt.Month switch
  217. {
  218. 1 => 31,
  219. 2 => (IsRuYear(dt.Year) ? 29 : 28),
  220. 3 => 31,
  221. 4 => 30,
  222. 5 => 31,
  223. 6 => 30,
  224. 7 => 31,
  225. 8 => 31,
  226. 9 => 30,
  227. 10 => 31,
  228. 11 => 30,
  229. 12 => 31,
  230. _ => 0
  231. };
  232. }
  233. /// <summary>返回当前日期的星期名称</summary>
  234. /// <param name="idt">日期</param>
  235. /// <returns>星期名称</returns>
  236. public static string GetWeekNameOfDay(this in DateTime idt)
  237. {
  238. return idt.DayOfWeek.ToString() switch
  239. {
  240. "Mondy" => "星期一",
  241. "Tuesday" => "星期二",
  242. "Wednesday" => "星期三",
  243. "Thursday" => "星期四",
  244. "Friday" => "星期五",
  245. "Saturday" => "星期六",
  246. "Sunday" => "星期日",
  247. _ => ""
  248. };
  249. }
  250. /// <summary>返回当前日期的星期编号</summary>
  251. /// <param name="idt">日期</param>
  252. /// <returns>星期数字编号</returns>
  253. public static string GetWeekNumberOfDay(this in DateTime idt)
  254. {
  255. return idt.DayOfWeek.ToString() switch
  256. {
  257. "Mondy" => "1",
  258. "Tuesday" => "2",
  259. "Wednesday" => "3",
  260. "Thursday" => "4",
  261. "Friday" => "5",
  262. "Saturday" => "6",
  263. "Sunday" => "7",
  264. _ => ""
  265. };
  266. }
  267. /// <summary>判断当前年份是否是闰年,私有函数</summary>
  268. /// <param name="iYear">年份</param>
  269. /// <returns>是闰年:True ,不是闰年:False</returns>
  270. private static bool IsRuYear(int iYear)
  271. {
  272. //形式参数为年份
  273. //例如:2003
  274. var n = iYear;
  275. return n % 400 == 0 || n % 4 == 0 && n % 100 != 0;
  276. }
  277. /// <summary>
  278. /// 判断是否为合法日期,必须大于1800年1月1日
  279. /// </summary>
  280. /// <param name="strDate">输入日期字符串</param>
  281. /// <returns>True/False</returns>
  282. public static bool IsDateTime(this string strDate)
  283. {
  284. DateTime.TryParse(strDate, out var result);
  285. return result.CompareTo(DateTime.Parse("1800-1-1")) > 0;
  286. }
  287. /// <summary>
  288. /// 判断时间是否在区间内
  289. /// </summary>
  290. /// <param name="this"></param>
  291. /// <param name="start">开始</param>
  292. /// <param name="end">结束</param>
  293. /// <param name="mode">模式</param>
  294. /// <returns></returns>
  295. public static bool In(this in DateTime @this, DateTime start, DateTime end, RangeMode mode = RangeMode.Close)
  296. {
  297. return mode switch
  298. {
  299. RangeMode.Open => start < @this && end > @this,
  300. RangeMode.Close => start <= @this && end >= @this,
  301. RangeMode.OpenClose => start < @this && end >= @this,
  302. RangeMode.CloseOpen => start <= @this && end > @this,
  303. _ => throw new ArgumentOutOfRangeException(nameof(mode), mode, null)
  304. };
  305. }
  306. /// <summary>
  307. /// 返回每月的第一天和最后一天
  308. /// </summary>
  309. /// <param name="_"></param>
  310. /// <param name="month">月份</param>
  311. /// <param name="firstDay">第一天</param>
  312. /// <param name="lastDay">最后一天</param>
  313. public static void ReturnDateFormat(this DateTime _, int month, out string firstDay, out string lastDay)
  314. {
  315. int year = DateTime.Now.Year + month / 12;
  316. if (month != 12)
  317. {
  318. month %= 12;
  319. }
  320. switch (month)
  321. {
  322. case 1:
  323. firstDay = DateTime.Now.ToString($"{year}-0{month}-01");
  324. lastDay = DateTime.Now.ToString($"{year}-0{month}-31");
  325. break;
  326. case 2:
  327. firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
  328. lastDay = DateTime.IsLeapYear(DateTime.Now.Year) ? DateTime.Now.ToString(year + "-0" + month + "-29") : DateTime.Now.ToString(year + "-0" + month + "-28");
  329. break;
  330. case 3:
  331. firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
  332. lastDay = DateTime.Now.ToString("yyyy-0" + month + "-31");
  333. break;
  334. case 4:
  335. firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
  336. lastDay = DateTime.Now.ToString(year + "-0" + month + "-30");
  337. break;
  338. case 5:
  339. firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
  340. lastDay = DateTime.Now.ToString(year + "-0" + month + "-31");
  341. break;
  342. case 6:
  343. firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
  344. lastDay = DateTime.Now.ToString(year + "-0" + month + "-30");
  345. break;
  346. case 7:
  347. firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
  348. lastDay = DateTime.Now.ToString(year + "-0" + month + "-31");
  349. break;
  350. case 8:
  351. firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
  352. lastDay = DateTime.Now.ToString(year + "-0" + month + "-31");
  353. break;
  354. case 9:
  355. firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
  356. lastDay = DateTime.Now.ToString(year + "-0" + month + "-30");
  357. break;
  358. case 10:
  359. firstDay = DateTime.Now.ToString(year + "-" + month + "-01");
  360. lastDay = DateTime.Now.ToString(year + "-" + month + "-31");
  361. break;
  362. case 11:
  363. firstDay = DateTime.Now.ToString(year + "-" + month + "-01");
  364. lastDay = DateTime.Now.ToString(year + "-" + month + "-30");
  365. break;
  366. default:
  367. firstDay = DateTime.Now.ToString(year + "-" + month + "-01");
  368. lastDay = DateTime.Now.ToString(year + "-" + month + "-31");
  369. break;
  370. }
  371. }
  372. /// <summary>
  373. /// 返回某年某月最后一天
  374. /// </summary>
  375. /// <param name="_"></param>
  376. /// <param name="year">年份</param>
  377. /// <param name="month">月份</param>
  378. /// <returns>日</returns>
  379. public static int GetMonthLastDate(this DateTime _, int year, int month)
  380. {
  381. DateTime lastDay = new DateTime(year, month, new GregorianCalendar().GetDaysInMonth(year, month));
  382. int day = lastDay.Day;
  383. return day;
  384. }
  385. /// <summary>
  386. /// 获得一段时间内有多少小时
  387. /// </summary>
  388. /// <param name="dtStar">起始时间</param>
  389. /// <param name="dtEnd">终止时间</param>
  390. /// <returns>小时差</returns>
  391. public static string GetTimeDelay(this in DateTime dtStar, DateTime dtEnd)
  392. {
  393. long lTicks = (dtEnd.Ticks - dtStar.Ticks) / 10000000;
  394. string sTemp = (lTicks / 3600).ToString().PadLeft(2, '0') + ":";
  395. sTemp += (lTicks % 3600 / 60).ToString().PadLeft(2, '0') + ":";
  396. sTemp += (lTicks % 3600 % 60).ToString().PadLeft(2, '0');
  397. return sTemp;
  398. }
  399. /// <summary>
  400. /// 获得8位时间整型数字
  401. /// </summary>
  402. /// <param name="dt">当前的日期时间对象</param>
  403. /// <returns>8位时间整型数字</returns>
  404. public static string GetDateString(this in DateTime dt)
  405. {
  406. return dt.Year + dt.Month.ToString().PadLeft(2, '0') + dt.Day.ToString().PadLeft(2, '0');
  407. }
  408. /// <summary>
  409. /// 返回时间差
  410. /// </summary>
  411. /// <param name="dateTime1">时间1</param>
  412. /// <param name="dateTime2">时间2</param>
  413. /// <returns>时间差</returns>
  414. public static string DateDiff(this in DateTime dateTime1, in DateTime dateTime2)
  415. {
  416. string dateDiff;
  417. var ts = dateTime2 - dateTime1;
  418. if (ts.Days >= 1)
  419. {
  420. dateDiff = dateTime1.Month + "月" + dateTime1.Day + "日";
  421. }
  422. else
  423. {
  424. dateDiff = ts.Hours > 1 ? ts.Hours + "小时前" : ts.Minutes + "分钟前";
  425. }
  426. return dateDiff;
  427. }
  428. /// <summary>
  429. /// 计算2个时间差
  430. /// </summary>
  431. /// <param name="beginTime">开始时间</param>
  432. /// <param name="endTime">结束时间</param>
  433. /// <returns>时间差</returns>
  434. public static string GetDiffTime(this in DateTime beginTime, in DateTime endTime)
  435. {
  436. string strResout = string.Empty;
  437. //获得2时间的时间间隔秒计算
  438. TimeSpan span = endTime.Subtract(beginTime);
  439. int sec = Convert.ToInt32(span.TotalSeconds);
  440. int minutes = 1 * 60;
  441. int hours = minutes * 60;
  442. int day = hours * 24;
  443. int month = day * 30;
  444. int year = month * 12;
  445. //提醒时间,到了返回1,否则返回0
  446. if (sec > year)
  447. {
  448. strResout += sec / year + "年";
  449. sec %= year; //剩余
  450. }
  451. if (sec > month)
  452. {
  453. strResout += sec / month + "月";
  454. sec %= month;
  455. }
  456. if (sec > day)
  457. {
  458. strResout += sec / day + "天";
  459. sec %= day;
  460. }
  461. if (sec > hours)
  462. {
  463. strResout += sec / hours + "小时";
  464. sec %= hours;
  465. }
  466. if (sec > minutes)
  467. {
  468. strResout += sec / minutes + "分";
  469. sec %= minutes;
  470. }
  471. strResout += sec + "秒";
  472. return strResout;
  473. }
  474. }
  475. /// <summary>
  476. /// 区间模式
  477. /// </summary>
  478. public enum RangeMode
  479. {
  480. /// <summary>
  481. /// 开区间
  482. /// </summary>
  483. Open,
  484. /// <summary>
  485. /// 闭区间
  486. /// </summary>
  487. Close,
  488. /// <summary>
  489. /// 左开右闭区间
  490. /// </summary>
  491. OpenClose,
  492. /// <summary>
  493. /// 左闭右开区间
  494. /// </summary>
  495. CloseOpen
  496. }
  497. }