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.

319 lines
12 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. using Apewer.Internals;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Globalization;
  6. using System.Text;
  7. namespace Apewer
  8. {
  9. /// <summary>时钟。</summary>
  10. public class ClockUtility
  11. {
  12. /// <summary>创建新的零值 DateTime 对象。</summary>
  13. public static DateTime Zero { get => new DateTime(0L, DateTimeKind.Utc); }
  14. /// <summary>获取一个 DateTime 对象,该对象设置为 1970-01-01 00:00:00.000。</summary>
  15. public static DateTime Origin { get => new DateTime(1970, 1, 1, 0, 0, 0, 0); }
  16. /// <summary>获取一个 DateTime 对象,该对象设置为此计算机上的当前日期和时间,表示为本地时间。</summary>
  17. public static DateTime Now { get => DateTime.Now; }
  18. /// <summary>获取一个 DateTime 对象,该对象设置为此计算机上的当前日期和时间,表示为协调通用时间 (UTC)。</summary>
  19. public static DateTime UtcNow { get => DateTime.UtcNow; }
  20. #region Common
  21. /// <summary>判断指定年份是闰年。</summary>
  22. public static bool IsLeapYear(int year)
  23. {
  24. if (year % 400 == 0) return true;
  25. if (year % 100 == 0) return false;
  26. if (year % 4 == 0) return true;
  27. return false;
  28. }
  29. /// <summary>判断指定年份是闰年。</summary>
  30. public static bool IsLeapYear(DateTime datetime) => IsLeapYear(SafeDateTime(datetime).Year);
  31. /// <summary>获取指定年月的天数。</summary>
  32. public static int MonthDays(int year, int month)
  33. {
  34. switch (month)
  35. {
  36. case 1: case 3: case 5: case 7: case 8: case 10: case 12: return 31;
  37. case 4: case 6: case 9: case 11: return 30;
  38. case 2: return IsLeapYear(year) ? 29 : 28;
  39. default: return 0;
  40. }
  41. }
  42. /// <summary>尝试获取安全的 DateTime 对象。</summary>
  43. public static DateTime SafeDateTime(object datetime)
  44. {
  45. if (datetime is DateTime)
  46. {
  47. var span = (DateTime)datetime - Origin;
  48. return Origin.AddMilliseconds(span.TotalMilliseconds);
  49. }
  50. else
  51. {
  52. if (datetime == null) return Zero;
  53. var type = datetime.GetType();
  54. if (type.Equals(typeof(string)))
  55. {
  56. var s = datetime as string;
  57. if (string.IsNullOrEmpty(s)) return Zero;
  58. DateTime value;
  59. var success = DateTime.TryParse(s, out value);
  60. return success ? value : Zero;
  61. }
  62. else
  63. {
  64. if (datetime == null) return Zero;
  65. try
  66. {
  67. var s = datetime.ToString();
  68. if (string.IsNullOrEmpty(s)) return Zero;
  69. return SafeDateTime(s);
  70. }
  71. catch { return Zero; }
  72. }
  73. }
  74. }
  75. #endregion
  76. #region Stamp
  77. /// <summary>获取当前本地时间的毫秒时间戳。</summary>
  78. public static long NowStamp { get => Stamp(Now); }
  79. /// <summary>获取当前 UTC 的毫秒时间戳。</summary>
  80. public static long UtcStamp { get => Stamp(UtcNow); }
  81. /// <summary>获取毫秒时间戳。</summary>
  82. public static long Stamp(DateTime datetime, bool byMilliseconds = true)
  83. {
  84. var span = datetime - Origin;
  85. var value = byMilliseconds ? span.TotalMilliseconds : span.TotalSeconds;
  86. var stamp = Convert.ToInt64(value);
  87. return stamp;
  88. }
  89. /// <summary>从毫秒时间戳获取 DateTime 对象。发生异常且不允许异常时将返回 1970-01-01 00:00:00.000。</summary>
  90. /// <exception cref="ArgumentOutOfRangeException"></exception>
  91. public static DateTime FromStamp(long stamp, bool throwException = true)
  92. {
  93. try
  94. {
  95. var datetime = Origin.AddMilliseconds(Convert.ToDouble(stamp));
  96. return datetime;
  97. }
  98. catch
  99. {
  100. if (throwException) throw new ArgumentOutOfRangeException();
  101. return Origin;
  102. }
  103. }
  104. #endregion
  105. #region Text
  106. /// <summary>解析文本,获取 DateTime 对象。</summary>
  107. public static Class<DateTime> FromText(string text)
  108. {
  109. var str = text;
  110. if (string.IsNullOrEmpty(str)) return null;
  111. var utc = false;
  112. var lower = str.ToLower();
  113. if (lower.EndsWith(" utc"))
  114. {
  115. utc = true;
  116. str = str.Substring(0, str.Length - 4);
  117. }
  118. DateTime dt;
  119. if (!DateTime.TryParse(str, out dt))
  120. {
  121. if (!str.Contains("-") && DateTime.TryParseExact(str, "yyyy-M-d", null, DateTimeStyles.None, out dt))
  122. {
  123. if (!str.Contains("/") && DateTime.TryParseExact(str, "yyyy/M/d", null, DateTimeStyles.None, out dt))
  124. {
  125. return null;
  126. }
  127. }
  128. }
  129. if (utc) dt = new DateTime(dt.Ticks, DateTimeKind.Utc);
  130. return new Class<DateTime>(dt);
  131. }
  132. #endregion
  133. #region Lucid & Compact
  134. /// <summary>表示当前本地时间的文本,显示为易于阅读的格式。</summary>
  135. public static string LucidNow { get => Lucid(Now); }
  136. /// <summary>表示当前 UTC 的文本,显示为易于阅读的格式。</summary>
  137. public static string LucidUtc { get => Lucid(UtcNow); }
  138. /// <summary>表示当前本地日期的文本,显示为易于阅读的格式。</summary>
  139. public static string LucidDate { get { return Lucid(DateTime.Now, true, false, false, false); } }
  140. /// <summary>表示当前本地时间的文本,显示为紧凑的格式。</summary>
  141. public static string CompactNow { get => Compact(Now); }
  142. /// <summary>表示当前 UTC 的文本,显示为紧凑的格式。</summary>
  143. public static string CompactUtc { get => Compact(UtcNow); }
  144. /// <summary>表示当前本地日期的文本,显示为紧凑的格式。</summary>
  145. public static string CompactDate { get { return Compact(DateTime.Now, true, false, false, false); } }
  146. /// <summary>转换 DateTime 对象到易于阅读的文本。</summary>
  147. public static string Lucid(DateTime datetime, bool date = true, bool time = true, bool seconds = true, bool milliseconds = true)
  148. {
  149. var safe = SafeDateTime(datetime);
  150. var sb = new StringBuilder();
  151. if (date) sb.Append(FormatDate(safe, true));
  152. if (time)
  153. {
  154. if (date) sb.Append(" ");
  155. sb.Append(FormatTime(safe, true, seconds, milliseconds));
  156. }
  157. var lucid = sb.ToString();
  158. return lucid;
  159. }
  160. /// <summary>转换 DateTime 对象到紧凑的文本。</summary>
  161. public static string Compact(DateTime datetime, bool date = true, bool time = true, bool seconds = true, bool milliseconds = true)
  162. {
  163. var safe = SafeDateTime(datetime);
  164. var sb = new StringBuilder();
  165. if (date) sb.Append(FormatDate(safe, false));
  166. if (time)
  167. {
  168. sb.Append(FormatTime(safe, false, seconds, milliseconds));
  169. }
  170. var lucid = sb.ToString();
  171. return lucid;
  172. }
  173. private static string FormatDate(DateTime datetime, bool lucid)
  174. {
  175. var sb = new StringBuilder();
  176. var y = NumberUtility.Restrict(datetime.Year, 0, 9999);
  177. var m = NumberUtility.Restrict(datetime.Month, 1, 12);
  178. var d = NumberUtility.Restrict(datetime.Day, 1, MonthDays(y, m));
  179. if (y < 10) sb.Append("000");
  180. else if (y < 100) sb.Append("00");
  181. else if (y < 1000) sb.Append("0");
  182. sb.Append(y.ToString());
  183. if (lucid) sb.Append("-");
  184. if (m < 10) sb.Append("0");
  185. sb.Append(m.ToString());
  186. if (lucid) sb.Append("-");
  187. if (d < 10) sb.Append("0");
  188. sb.Append(d.ToString());
  189. var date = sb.ToString();
  190. return date;
  191. }
  192. private static string FormatTime(DateTime datetime, bool lucid, bool seconds, bool milliseconds)
  193. {
  194. var sb = new StringBuilder();
  195. var h = NumberUtility.Restrict(datetime.Hour, 0, 23);
  196. var m = NumberUtility.Restrict(datetime.Minute, 0, 59);
  197. var s = NumberUtility.Restrict(datetime.Second, 0, 59);
  198. var ms = NumberUtility.Restrict(datetime.Millisecond, 0, 999);
  199. if (h < 10) sb.Append("0");
  200. sb.Append(h.ToString());
  201. if (lucid) sb.Append(":");
  202. if (m < 10) sb.Append("0");
  203. sb.Append(m.ToString());
  204. if (seconds)
  205. {
  206. if (lucid) sb.Append(":");
  207. if (s < 10) sb.Append("0");
  208. sb.Append(s.ToString());
  209. if (milliseconds)
  210. {
  211. if (lucid) sb.Append(".");
  212. if (ms < 10) sb.Append("00");
  213. else if (ms < 100) sb.Append("0");
  214. sb.Append(ms.ToString());
  215. }
  216. }
  217. var time = sb.ToString();
  218. return time;
  219. }
  220. /// <summary>解析 Lucid 文本。</summary>
  221. public static Nullable<DateTime> ParseLucid(string lucid)
  222. {
  223. var failed = new Nullable<DateTime>();
  224. if (lucid.IsEmpty()) return failed;
  225. int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, milli = 0;
  226. if (lucid.Length < 10) return failed;
  227. if (lucid[4] != '-' || lucid[7] != '-') return failed;
  228. year = NumberUtility.Int32(lucid.Substring(0, 4));
  229. month = NumberUtility.Int32(lucid.Substring(5, 2));
  230. day = NumberUtility.Int32(lucid.Substring(8, 2));
  231. if (year < 1) return failed;
  232. if (month < 1 || month > 12) return failed;
  233. if (day < 1 || day > DateTime.DaysInMonth(year, month)) return failed;
  234. if (lucid.Length >= 16)
  235. {
  236. if (lucid[10] != ' ' || lucid[13] != ':') return failed;
  237. hour = NumberUtility.Int32(lucid.Substring(11, 2));
  238. minute = NumberUtility.Int32(lucid.Substring(14, 2));
  239. if (hour < 0 || hour > 23) return failed;
  240. if (minute < 0 || minute > 59) return failed;
  241. if (lucid.Length >= 19)
  242. {
  243. if (lucid[16] != ':') return failed;
  244. second = NumberUtility.Int32(lucid.Substring(17, 2));
  245. if (second < 0 || second > 59) return failed;
  246. if (lucid.Length >= 23)
  247. {
  248. if (lucid[19] != '.') return failed;
  249. milli = NumberUtility.Int32(lucid.Substring(20, 3));
  250. if (milli < 0 || milli > 999) return failed;
  251. }
  252. }
  253. }
  254. var entity = new DateTime(year, month, day, hour, minute, second, milli);
  255. return new Nullable<DateTime>(entity);
  256. }
  257. #endregion
  258. }
  259. }