早就萌生了写博客的想法,一直到现在才动手,原因有多方面,归根结底就是一个字~懒。
今天无意看到一片博文,觉得里面说得几点原因很对,原文地址:我们为什么应该坚持写博客,感谢作者,让我有动力写了这篇博文。其实写博文是想记录自己遇到的一些问题的解决思路,方便以后查阅,同时希望可以跟大家一起交流提高。
先介绍下本人的基本情况,本人今年刚毕业,坐标上海,.NET 菜鸟一枚,第一次写博客,有意见欢迎大家提出,大神轻喷!
好了,废话不多说,开门见山。
最近在公司开发的系统中,需要计算工作日,就是给出一个采购周期(n天),我需要计算出在n个工作日之后的日期。开始准备去调接口(ps:找了半天发现没有太合适的,还有吐槽下国家政府单位都没有官方接口的),但是负责这个项目的大佬说,万一别个的接口崩了,会影响我们自己的系统的正常运行,自己开发还是稳点,我就写了这个功能,特此记录下实现这个功能的思路。
工作日想必大家都知道,就是除去周末和每年国务院颁布的节假日放假安排(例如:2017年部分节假日安排),其他就都是工作日(对了,差点忘记补班,这也算是工作日哦)。
“废话”说的够多了,下面撸起袖子开干吧,代码都写了注释。
提供了两个公共方法,先给大家看下简单测试的运行结果:
(1).根据传入的工作日天数,获得计算后的日期
(2).根据传入的时间,计算工作日天数;
具体代码:
class="code_img_closed" src="/Upload/Images/2017110517/0015B68B3C38AA5B.gif" alt="">1 public class HolidayHelper 2 { 3 #region 字段属性 4 private static object _syncObj = new object(); 5 private static HolidayHelper _instance { get; set; } 6 private HolidayHelper() { } 7 private static List<DateModel> cacheDateList = null; 8 public static HolidayHelper Instance 9 { 10 get 11 { 12 lock (_syncObj) 13 { 14 _instance = new HolidayHelper(); 15 } 16 return _instance; 17 } 18 } 19 #endregion 20 21 #region 私有方法 22 /// <summary> 23 /// 读取文件 24 /// </summary> 25 /// <param name="filePath"></param> 26 /// <returns></returns> 27 private string GetFileContent(string filePath) 28 { 29 string result = ""; 30 if (File.Exists(filePath)) 31 { 32 result = File.ReadAllText(filePath); 33 } 34 return result; 35 } 36 /// <summary> 37 /// 获取配置的Json文件 38 /// </summary> 39 /// <returns>经过反序列化之后的对象集合</returns> 40 private List<DateModel> GetConfigList() 41 { 42 if (cacheDateList == null) 43 { 44 string path = string.Format("{0}/../../Config/holidayConfig.json", System.AppDomain.CurrentDomain.BaseDirectory); 45 string fileContent = GetFileContent(path); 46 if (!string.IsNullOrWhiteSpace(fileContent)) 47 { 48 cacheDateList = Newtonsoft.Json.JsonConvert.DeserializeObject<List<DateModel>>(fileContent); 49 } 50 } 51 return cacheDateList; 52 } 53 /// <summary> 54 /// 获取指定年份的数据 55 /// </summary> 56 /// <param name="year"></param> 57 /// <returns></returns> 58 private DateModel GetConfigDataByYear(int year) 59 { 60 List<DateModel> dataSource = GetConfigList(); 61 DateModel result = dataSource.FirstOrDefault(m => m.Year == year); 62 return result; 63 } 64 /// <summary> 65 /// 判断是否为工作日 66 /// </summary> 67 /// <param name="currDate">要判断的时间</param> 68 /// <param name="thisYearData">当前的数据</param> 69 /// <returns></returns> 70 private bool IsWorkDay(DateTime currDate, DateModel thisYearData) 71 { 72 if (currDate.Year != thisYearData.Year)//跨年重新读取数据 73 { 74 thisYearData = GetConfigDataByYear(currDate.Year); 75 } 76 if (thisYearData != null) 77 { 78 string date = currDate.ToString("MMdd"); 79 int week = (int)currDate.DayOfWeek; 80 81 if (thisYearData.Work.IndexOf(date) >= 0) 82 { 83 return true; 84 } 85 86 if (thisYearData.Holiday.IndexOf(date) >= 0) 87 { 88 return false; 89 } 90 91 if (week != 0 && week != 6) 92 { 93 return true; 94 } 95 } 96 return false; 97 } 98 99 #endregion 100 101 #region 公共方法 102 public void CleraCacheData() 103 { 104 if (cacheDateList != null) 105 { 106 cacheDateList.Clear(); 107 } 108 } 109 /// <summary> 110 /// 根据传入的工作日天数,获得计算后的日期,可传负数 111 /// </summary> 112 /// <param name="day">天数</param> 113 /// <param name="isContainToday">当天是否算工作日(默认:true)</param> 114 /// <returns></returns> 115 public DateTime GetReckonDate(int day, bool isContainToday = true) 116 { 117 DateTime currDate = DateTime.Now; 118 int addDay = day >= 0 ? 1 : -1; 119 120 if (isContainToday) 121 currDate = currDate.AddDays(-addDay); 122 123 DateModel thisYearData = GetConfigDataByYear(currDate.Year); 124 if (thisYearData != null) 125 { 126 int sumDay = Math.Abs(day); 127 int workDayNum = 0; 128 while (workDayNum < sumDay) 129 { 130 currDate = currDate.AddDays(addDay); 131 if (IsWorkDay(currDate, thisYearData)) 132 workDayNum++; 133 } 134 } 135 return currDate; 136 } 137 138 /// <summary> 139 /// 根据传入的时间,计算工作日天数 140 /// </summary> 141 /// <param name="date">带计算的时间</param> 142 /// <param name="isContainToday">当天是否算工作日(默认:true)</param> 143 /// <returns></returns> 144 public int GetWorkDayNum(DateTime date, bool isContainToday = true) 145 { 146 var currDate = DateTime.Now; 147 148 int workDayNum = 0; 149 int addDay = date.Date > currDate.Date ? 1 : -1; 150 151 if (isContainToday) 152 { 153 currDate = currDate.AddDays(-addDay); 154 } 155 156 DateModel thisYearData = GetConfigDataByYear(currDate.Year); 157 if (thisYearData != null) 158 { 159 bool isEnd = false; 160 do 161 { 162 currDate = currDate.AddDays(addDay); 163 if (IsWorkDay(currDate, thisYearData)) 164 workDayNum += addDay; 165 isEnd = addDay > 0 ? (date.Date > currDate.Date) : (date.Date < currDate.Date); 166 } while (isEnd); 167 } 168 return workDayNum; 169 } 170 #endregion 171 } 172 173 public class DateModel 174 { 175 public int Year { get; set; } 176 177 public List<string> Work { get; set; } 178 179 public List<string> Holiday { get; set; } 180 }logs_code_collapse">View Code
说明下,法定节假日我是自己用json来配置的,大家可以自己维护,或者做成自己的接口。下面展示下json的格式,这是我自己配置的(2015-2017年),大家可以按照自己的需求来修改。
1 [ 2 { 3 "Year": "2015", 4 "Work": [ "0104", "0215", "0228", "0906", "1010" ], 5 "Holiday": [ "0101", "0102", "0103", "0218", "0219", "0220", "0221", "0222", "0223", "0224", "0404", "0405", "0406", "0501", "0502", "0503", "0620", "0621", "0622", "0903", "0904", "0905", "0927", "1001", "1002", "1003", "1004", "1005", "1006", "1007" ] 6 }, 7 { 8 "Year": "2016", 9 "Work": [ "0206", "0214", "0612", "0918", "1008", "1009" ], 10 "Holiday": [ "0101", "0207", "0208", "0209", "0210", "0211", "0212", "0213", "0404", "0501", "0502", "0609", "0610", "0611", "0915", "0916", "0917", "1001", "1002", "1003", "1004", "1005", "1006", "1007" ] 11 }, 12 { 13 "Year": "2017", 14 "Work": [ "0122", "0204", "0401", "0527", "0930" ], 15 "Holiday": [ "0101", "0102", "0127", "0128", "0129", "0130", "0201", "0202", "0501", "0529", "0530", "1001", "1002", "1003", "1004", "1005", "1006" ] 16 } 17 ]holidayConfig.json
好了,就说这么多,由于能力有限,有写得不好的地方,欢迎指正、补充。如果对您有帮助,请帮忙点个赞,谢谢!