C#-中文日期转换为 DateTime

2021年10月20日 14:24 · 阅读(1020) ·

参考

几个C#日期、时间验证的正则表达式

C# 阿拉伯数字转换为中文数字/中文数字转换为阿拉伯数字

问题描述

中文格式的日期,比如 二零二一年九月一十三日二〇二一年九月一十三日,转换为 DateTime

日期帮助类

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. namespace Luoma.Common.Utils
  8. {
  9. public class DateTimeUtils
  10. {
  11. /// <summary>
  12. /// 字符串日期转 DateTime
  13. /// </summary>
  14. /// <param name="strDateTime">字符串日期</param>
  15. /// <param name="dt">转换成功赋值</param>
  16. /// <returns>转换成功返回 true</returns>
  17. public static bool TransStrToDateTime(string str, out DateTime dt)
  18. {
  19. //第一次转换
  20. if (DateTime.TryParse(str, out dt))
  21. {
  22. return true;
  23. }
  24. //第二次转换
  25. string[] format = new string[]
  26. {
  27. "yyyyMMdd",
  28. "yyyyMdHHmmss",
  29. "yyyyMMddHHmmss",
  30. "yyyy-M-d",
  31. "yyyy-MM-dd",
  32. "yyyy-MM-dd HH:mm:ss",
  33. "yyyy/M/d",
  34. "yyyy/MM/dd",
  35. "yyyy/MM/dd HH:mm:ss",
  36. "yyyy.M.d",
  37. "yyyy.MM.dd",
  38. "yyyy.MM.dd HH:mm:ss",
  39. "yyyy年M月d日",
  40. "yyyy年MM月dd日",
  41. "yyyy年MM月dd日HH:mm:ss",
  42. "yyyy年MM月dd日 HH时mm分ss秒"
  43. };
  44. if (DateTime.TryParseExact(str, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out dt))
  45. {
  46. return true;
  47. }
  48. //第三次转换
  49. try
  50. {
  51. if (Regex.IsMatch(str, "^(零|〇|一|二|三|四|五|六|七|八|九|十){2,4}年((正|一|二|三|四|五|六|七|八|九|十|十一|十二)月((一|二|三|四|五|六|七|八|九|十){1,3}(日)?)?)?$"))
  52. {
  53. Match match = Regex.Match(str, @"^(.+)年(.+)月(.+)日$");
  54. if (match.Success)
  55. {
  56. int year = GetYear(match.Groups[1].Value);
  57. int month = GetMonth(match.Groups[2].Value);
  58. long dayL = ParseCnToInt(match.Groups[3].Value);
  59. dt = new DateTime(year, month, int.Parse(dayL.ToString()));
  60. return true;
  61. }
  62. }
  63. }
  64. catch
  65. {
  66. return false;
  67. }
  68. return false;
  69. }
  70. /// <summary>
  71. /// 使用正则表达式判断是否为日期
  72. /// </summary>
  73. /// <param name="str">日期格式字符串</param>
  74. /// <returns>是日期格式字符串返回 true</returns>
  75. public static bool IsDateTime(string str)
  76. {
  77. bool isDateTime = false;
  78. // yyyy/MM/dd - 年月日数字
  79. if (Regex.IsMatch(str, "^(?<year>\\d{2,4})/(?<month>\\d{1,2})/(?<day>\\d{1,2})$"))
  80. isDateTime = true;
  81. // yyyy-MM-dd - 年月日数字
  82. else if (Regex.IsMatch(str, "^(?<year>\\d{2,4})-(?<month>\\d{1,2})-(?<day>\\d{1,2})$"))
  83. isDateTime = true;
  84. // yyyy.MM.dd - 年月日数字
  85. else if (Regex.IsMatch(str, "^(?<year>\\d{2,4})[.](?<month>\\d{1,2})[.](?<day>\\d{1,2})$"))
  86. isDateTime = true;
  87. // yyyy年MM月dd日 - 年月日数字
  88. else if (Regex.IsMatch(str, "^((?<year>\\d{2,4})年)?(?<month>\\d{1,2})月((?<day>\\d{1,2})日)?$"))
  89. isDateTime = true;
  90. // yyyy年MM月dd日 - 年月日中文
  91. else if (Regex.IsMatch(str, "^(零|〇|一|二|三|四|五|六|七|八|九|十){2,4}年((正|一|二|三|四|五|六|七|八|九|十|十一|十二)月((一|二|三|四|五|六|七|八|九|十){1,3}(日)?)?)?$"))
  92. isDateTime = true;
  93. // yyyy年MM月dd日 - 年(数字),月(中文),日(中文)
  94. //else if (Regex.IsMatch(str, "^((?<year>\\d{2,4})年)?(正|一|二|三|四|五|六|七|八|九|十|十一|十二)月((一|二|三|四|五|六|七|八|九|十){1,3}日)?$"))
  95. // isDateTime = true;
  96. // yyyy年
  97. //else if (Regex.IsMatch(str, "^(?<year>\\d{2,4})年$"))
  98. // isDateTime = true;
  99. // 农历1
  100. //else if (Regex.IsMatch(str, "^(甲|乙|丙|丁|戊|己|庚|辛|壬|癸)(子|丑|寅|卯|辰|巳|午|未|申|酉|戌|亥)年((正|一|二|三|四|五|六|七|八|九|十|十一|十二)月((一|二|三|四|五|六|七|八|九|十){1,3}(日)?)?)?$"))
  101. // isDateTime = true;
  102. //// 农历2
  103. //else if (Regex.IsMatch(str, "^((甲|乙|丙|丁|戊|己|庚|辛|壬|癸)(子|丑|寅|卯|辰|巳|午|未|申|酉|戌|亥)年)?(正|一|二|三|四|五|六|七|八|九|十|十一|十二)月初(一|二|三|四|五|六|七|八|九|十)$"))
  104. // isDateTime = true;
  105. //// XX时XX分XX秒
  106. //else if (Regex.IsMatch(str, "^(?<hour>\\d{1,2})(时|点)(?<minute>\\d{1,2})分((?<second>\\d{1,2})秒)?$"))
  107. // isDateTime = true;
  108. //// XX时XX分XX秒
  109. //else if (Regex.IsMatch(str, "^((零|一|二|三|四|五|六|七|八|九|十){1,3})(时|点)((零|一|二|三|四|五|六|七|八|九|十){1,3})分(((零|一|二|三|四|五|六|七|八|九|十){1,3})秒)?$"))
  110. // isDateTime = true;
  111. //// XX分XX秒
  112. //else if (Regex.IsMatch(str, "^(?<minute>\\d{1,2})分(?<second>\\d{1,2})秒$"))
  113. // isDateTime = true;
  114. //// XX分XX秒
  115. //else if (Regex.IsMatch(str, "^((零|一|二|三|四|五|六|七|八|九|十){1,3})分((零|一|二|三|四|五|六|七|八|九|十){1,3})秒$"))
  116. // isDateTime = true;
  117. //// XX时
  118. //else if (Regex.IsMatch(str, "\\b(?<hour>\\d{1,2})(时|点钟)\\b"))
  119. // isDateTime = true;
  120. else
  121. isDateTime = false;
  122. return isDateTime;
  123. }
  124. #region 年月获取
  125. /// <summary>
  126. /// 获取年份
  127. /// </summary>
  128. /// <param name="str">年份</param>
  129. /// <returns>数字年份</returns>
  130. public static int GetYear(string str)
  131. {
  132. int number = 0;
  133. string strNumber = "";
  134. foreach (char item in str)
  135. {
  136. switch (item.ToString())
  137. {
  138. case "零":
  139. case "〇":
  140. strNumber += "0";
  141. break;
  142. case "一":
  143. strNumber += "1";
  144. break;
  145. case "二":
  146. strNumber += "2";
  147. break;
  148. case "三":
  149. strNumber += "3";
  150. break;
  151. case "四":
  152. strNumber += "4";
  153. break;
  154. case "五":
  155. strNumber += "5";
  156. break;
  157. case "六":
  158. strNumber += "6";
  159. break;
  160. case "七":
  161. strNumber += "7";
  162. break;
  163. case "八":
  164. strNumber += "8";
  165. break;
  166. case "九":
  167. strNumber += "9";
  168. break;
  169. case "十":
  170. strNumber += "10";
  171. break;
  172. }
  173. }
  174. int.TryParse(strNumber, out number);
  175. return number;
  176. }
  177. /// <summary>
  178. ///获取月份
  179. /// </summary>
  180. /// <param name="str">月份</param>
  181. /// <returns>数字月份</returns>
  182. public static int GetMonth(string str)
  183. {
  184. int number = 0;
  185. string strNumber = "";
  186. switch (str)
  187. {
  188. case "一":
  189. case "正":
  190. strNumber += "1";
  191. break;
  192. case "二":
  193. strNumber += "2";
  194. break;
  195. case "三":
  196. strNumber += "3";
  197. break;
  198. case "四":
  199. strNumber += "4";
  200. break;
  201. case "五":
  202. strNumber += "5";
  203. break;
  204. case "六":
  205. strNumber += "6";
  206. break;
  207. case "七":
  208. strNumber += "7";
  209. break;
  210. case "八":
  211. strNumber += "8";
  212. break;
  213. case "九":
  214. strNumber += "9";
  215. break;
  216. case "十":
  217. strNumber += "10";
  218. break;
  219. case "十一":
  220. strNumber += "11";
  221. break;
  222. case "十二":
  223. strNumber += "12";
  224. break;
  225. }
  226. int.TryParse(strNumber, out number);
  227. return number;
  228. }
  229. #endregion
  230. #region 中文数字和阿拉伯数字转换
  231. /// <summary>
  232. /// 阿拉伯数字转换成中文数字
  233. /// </summary>
  234. /// <param name="x"></param>
  235. /// <returns></returns>
  236. public static string NumToChinese(string x)
  237. {
  238. string[] pArrayNum = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" };
  239. //为数字位数建立一个位数组
  240. string[] pArrayDigit = { "", "十", "百", "千" };
  241. //为数字单位建立一个单位数组
  242. string[] pArrayUnits = { "", "万", "亿", "万亿" };
  243. var pStrReturnValue = ""; //返回值
  244. var finger = 0; //字符位置指针
  245. var pIntM = x.Length % 4; //取模
  246. int pIntK;
  247. if (pIntM > 0)
  248. pIntK = x.Length / 4 + 1;
  249. else
  250. pIntK = x.Length / 4;
  251. //外层循环,四位一组,每组最后加上单位: ",万亿,",",亿,",",万,"
  252. for (var i = pIntK; i > 0; i--)
  253. {
  254. var pIntL = 4;
  255. if (i == pIntK && pIntM != 0)
  256. pIntL = pIntM;
  257. //得到一组四位数
  258. var four = x.Substring(finger, pIntL);
  259. var P_int_l = four.Length;
  260. //内层循环在该组中的每一位数上循环
  261. for (int j = 0; j < P_int_l; j++)
  262. {
  263. //处理组中的每一位数加上所在的位
  264. int n = Convert.ToInt32(four.Substring(j, 1));
  265. if (n == 0)
  266. {
  267. if (j < P_int_l - 1 && Convert.ToInt32(four.Substring(j + 1, 1)) > 0 && !pStrReturnValue.EndsWith(pArrayNum[n]))
  268. pStrReturnValue += pArrayNum[n];
  269. }
  270. else
  271. {
  272. if (!(n == 1 && (pStrReturnValue.EndsWith(pArrayNum[0]) | pStrReturnValue.Length == 0) && j == P_int_l - 2))
  273. pStrReturnValue += pArrayNum[n];
  274. pStrReturnValue += pArrayDigit[P_int_l - j - 1];
  275. }
  276. }
  277. finger += pIntL;
  278. //每组最后加上一个单位:",万,",",亿," 等
  279. if (i < pIntK) //如果不是最高位的一组
  280. {
  281. if (Convert.ToInt32(four) != 0)
  282. //如果所有4位不全是0则加上单位",万,",",亿,"等
  283. pStrReturnValue += pArrayUnits[i - 1];
  284. }
  285. else
  286. {
  287. //处理最高位的一组,最后必须加上单位
  288. pStrReturnValue += pArrayUnits[i - 1];
  289. }
  290. }
  291. return pStrReturnValue;
  292. }
  293. /// <summary>
  294. /// 转换数字
  295. /// </summary>
  296. public static long CharToNumber(char c)
  297. {
  298. switch (c)
  299. {
  300. case '一': return 1;
  301. case '二': return 2;
  302. case '三': return 3;
  303. case '四': return 4;
  304. case '五': return 5;
  305. case '六': return 6;
  306. case '七': return 7;
  307. case '八': return 8;
  308. case '九': return 9;
  309. case '零': return 0;
  310. default: return -1;
  311. }
  312. }
  313. /// <summary>
  314. /// 转换单位
  315. /// </summary>
  316. public static long CharToUnit(char c)
  317. {
  318. switch (c)
  319. {
  320. case '十': return 10;
  321. case '百': return 100;
  322. case '千': return 1000;
  323. case '万': return 10000;
  324. case '亿': return 100000000;
  325. default: return 1;
  326. }
  327. }
  328. /// <summary>
  329. /// 将中文数字转换阿拉伯数字
  330. /// </summary>
  331. /// <param name="cnum">汉字数字</param>
  332. /// <returns>长整型阿拉伯数字</returns>
  333. public static long ParseCnToInt(string cnum)
  334. {
  335. cnum = Regex.Replace(cnum, "\\s+", "");
  336. long firstUnit = 1;//一级单位
  337. long secondUnit = 1;//二级单位
  338. long result = 0;//结果
  339. for (var i = cnum.Length - 1; i > -1; --i)//从低到高位依次处理
  340. {
  341. var tmpUnit = CharToUnit(cnum[i]);//临时单位变量
  342. if (tmpUnit > firstUnit)//判断此位是数字还是单位
  343. {
  344. firstUnit = tmpUnit;//是的话就赋值,以备下次循环使用
  345. secondUnit = 1;
  346. if (i == 0)//处理如果是"十","十一"这样的开头的
  347. {
  348. result += firstUnit * secondUnit;
  349. }
  350. continue;//结束本次循环
  351. }
  352. if (tmpUnit > secondUnit)
  353. {
  354. secondUnit = tmpUnit;
  355. continue;
  356. }
  357. result += firstUnit * secondUnit * CharToNumber(cnum[i]);//如果是数字,则和单位想乘然后存到结果里
  358. }
  359. return result;
  360. }
  361. #endregion
  362. }
  363. }

测试

  1. static void Main(string[] args)
  2. {
  3. DateTime time = new DateTime();
  4. string str = "二零二一年九月一十三日";
  5. DateTimeUtils.TransStrToDateTime(str, out time);
  6. Console.WriteLine(time.ToString("yyyy-MM-dd"));
  7. str = "2021/01/01";
  8. DateTimeUtils.TransStrToDateTime(str, out time);
  9. Console.WriteLine(time.ToString("yyyy-MM-dd"));
  10. }

输出

  1. 2021-09-13
  2. 2021-01-01