zoukankan      html  css  js  c++  java
  • C#实现工作日和休息日(包括法定节假日)的计算

      先介绍下本人的基本情况,本人今年刚毕业,坐标上海,.NET 菜鸟一枚,第一次写博客,有意见欢迎大家提出,大神轻喷!

      好了,废话不多说,开门见山。

    一、开发背景:

      最近在公司开发的系统中,需要计算工作日,就是给出一个采购周期(n天),我需要计算出在n个工作日之后的日期。开始准备去调接口(ps:找了半天发现没有太合适的,还有吐槽下国家政府单位都没有官方接口的),但是负责这个项目的大佬说,万一别个的接口崩了,会影响我们自己的系统的正常运行,自己开发还是稳点,我就写了这个功能,特此记录下实现这个功能的思路。

    二、定义:

      工作日想必大家都知道,就是除去周末和每年国务院颁布的节假日放假安排(例如:2017年部分节假日安排),其他就都是工作日(对了,差点忘记补班,这也算是工作日哦)。

    三、实践:

      “废话”说的够多了,下面撸起袖子开干吧,代码都写了注释。

      提供了两个公共方法,先给大家看下简单测试的运行结果:

        (1).根据传入的工作日天数,获得计算后的日期

        

        (2).根据传入的时间,计算工作日天数;

        

      具体代码:

      1 public class HolidayHelper
      2     {
      3         #region 字段属性
      4         private static object _syncObj = new object();
      5         private static HolidayHelper _instance { get; set; }
      6         private static List<DateModel> cacheDateList { get; set; }
      7         private HolidayHelper() { }
      8         /// <summary>
      9         /// 获得单例对象,使用懒汉式(双重锁定)
     10         /// </summary>
     11         /// <returns></returns>
     12         public static HolidayHelper GetInstance()
     13         {
     14             if (_instance == null)
     15             {
     16                 lock (_syncObj)
     17                 {
     18                     if (_instance == null)
     19                     {
     20                         _instance = new HolidayHelper();
     21                     }
     22                 }
     23             }
     24             return _instance;
     25         }
     26         #endregion
     27 
     28         #region 私有方法
     29         /// <summary>
     30         /// 读取文件
     31         /// </summary>
     32         /// <param name="filePath"></param>
     33         /// <returns></returns>
     34         private string GetFileContent(string filePath)
     35         {
     36             string result = "";
     37             if (File.Exists(filePath))
     38             {
     39                 result = File.ReadAllText(filePath);
     40             }
     41             return result;
     42         }
     43         /// <summary>
     44         /// 获取配置的Json文件
     45         /// </summary>
     46         /// <returns>经过反序列化之后的对象集合</returns>
     47         private List<DateModel> GetConfigList()
     48         {
     49             string path = string.Format("{0}/../../Config/holidayConfig.json", System.AppDomain.CurrentDomain.BaseDirectory);
     50             string fileContent = GetFileContent(path);
     51             if (!string.IsNullOrWhiteSpace(fileContent))
     52             {
     53                 cacheDateList = Newtonsoft.Json.JsonConvert.DeserializeObject<List<DateModel>>(fileContent);
     54             }
     55             return cacheDateList;
     56         }
     57         /// <summary>
     58         /// 获取指定年份的数据
     59         /// </summary>
     60         /// <param name="year"></param>
     61         /// <returns></returns>
     62         private DateModel GetConfigDataByYear(int year)
     63         {
     64             if (cacheDateList == null)//取配置数据
     65                 GetConfigList();
     66             DateModel result = cacheDateList.FirstOrDefault(m => m.Year == year);
     67             return result;
     68         }
     69         /// <summary>
     70         /// 判断是否为工作日
     71         /// </summary>
     72         /// <param name="currDate">要判断的时间</param>
     73         /// <param name="thisYearData">当前的数据</param>
     74         /// <returns></returns>
     75         private bool IsWorkDay(DateTime currDate, DateModel thisYearData)
     76         {
     77             if (currDate.Year != thisYearData.Year)//跨年重新读取数据
     78             {
     79                 thisYearData = GetConfigDataByYear(currDate.Year);
     80             }
     81             if (thisYearData.Year > 0)
     82             {
     83                 string date = currDate.ToString("MMdd");
     84                 int week = (int)currDate.DayOfWeek;
     85 
     86                 if (thisYearData.Work.IndexOf(date) >= 0)
     87                 {
     88                     return true;
     89                 }
     90 
     91                 if (thisYearData.Holiday.IndexOf(date) >= 0)
     92                 {
     93                     return false;
     94                 }
     95 
     96                 if (week != 0 && week != 6)
     97                 {
     98                     return true;
     99                 }
    100             }
    101             return false;
    102         }
    103 
    104         #endregion
    105 
    106         #region 公共方法
    107         public void CleraCacheData()
    108         {
    109             if (cacheDateList != null)
    110             {
    111                 cacheDateList.Clear();
    112             }
    113         }
    114         /// <summary>
    115         /// 根据传入的工作日天数,获得计算后的日期,可传负数
    116         /// </summary>
    117         /// <param name="day">天数</param>
    118         /// <param name="isContainToday">当天是否算工作日(默认:true)</param>
    119         /// <returns></returns>
    120         public DateTime GetReckonDate(int day, bool isContainToday = true)
    121         {
    122             DateTime currDate = DateTime.Now;
    123             int addDay = day >= 0 ? 1 : -1;
    124 
    125             if (isContainToday)
    126                 currDate = currDate.AddDays(-addDay);
    127 
    128             DateModel thisYearData = GetConfigDataByYear(currDate.Year);
    129             if (thisYearData.Year > 0)
    130             {
    131                 int sumDay = Math.Abs(day);
    132                 int workDayNum = 0;
    133                 while (workDayNum < sumDay)
    134                 {
    135                     currDate = currDate.AddDays(addDay);
    136                     if (IsWorkDay(currDate, thisYearData))
    137                         workDayNum++;
    138                 }
    139             }
    140             return currDate;
    141         }
    142         /// <summary>
    143         /// 根据传入的时间,计算工作日天数
    144         /// </summary>
    145         /// <param name="date">带计算的时间</param>
    146         /// <param name="isContainToday">当天是否算工作日(默认:true)</param>
    147         /// <returns></returns>
    148         public int GetWorkDayNum(DateTime date, bool isContainToday = true)
    149         {
    150             var currDate = DateTime.Now;
    151 
    152             int workDayNum = 0;
    153             int addDay = date.Date > currDate.Date ? 1 : -1;
    154 
    155             if (isContainToday)
    156             {
    157                 currDate = currDate.AddDays(-addDay);
    158             }
    159 
    160             DateModel thisYearData = GetConfigDataByYear(currDate.Year);
    161             if (thisYearData.Year > 0)
    162             {
    163                 bool isEnd = false;
    164                 do
    165                 {
    166                     currDate = currDate.AddDays(addDay);
    167                     if (IsWorkDay(currDate, thisYearData))
    168                         workDayNum += addDay;
    169                     isEnd = addDay > 0 ? (date.Date > currDate.Date) : (date.Date < currDate.Date);
    170                 } while (isEnd);
    171             }
    172             return workDayNum;
    173         }
    174         #endregion
    175     }
    176 
    177     public struct DateModel
    178     {
    179         public int Year { get; set; }
    180 
    181         public List<string> Work { get; set; }
    182 
    183         public List<string> Holiday { get; set; }
    184     }
    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

      好了,就说这么多,由于能力有限,有写得不好的地方,欢迎指正、补充。如果对您有帮助,请帮忙点个赞,谢谢!

  • 相关阅读:
    maven中net.sf.json报错的解决方法(转载)
    [PY3]——环境配置(1)——pyenv | pip | ipython | jupyter(含安装pyenv环境shell脚本)
    [LNMP]——LNMP环境配置
    Tomcat
    Amoeba+Mysql 实现读写分离
    LVS+keepalived DR模式配置高可用负载均衡集群
    [Mysql高可用]——双主互备+keepalived
    Mysql 日志管理
    Mysql基本操作总结
    [Mysql]——通过例子理解事务的4种隔离级别
  • 原文地址:https://www.cnblogs.com/yuan-chong/p/HolidayHelper.html
Copyright © 2011-2022 走看看