转自:http://www.cnblogs.com/yuan-chong/p/HolidayHelper.html

一、开发背景:

  最近在公司开发的系统中,需要计算工作日,就是给出一个采购周期(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. }

  说明下,法定节假日我是自己用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. ]
  18.  
  19. holidayConfig.json

  

C#实现工作日和休息日(包括法定节假日)的计算的更多相关文章

  1. java 查询指定月份的工作日(不包括法定节假日)

    /** * 日期工具类 用于获取指定月份的工作日(除去周末和法定节假日) */ public class DateUtils { public static void main(String[] ar ...

  2. 调用免费API查询全年工作日、周末、法定节假日、节假日调休补班数据

    前言 日常开发中,难免会用到判断今天是工作日.周末.法定节假日.节假日调休补班做一些业务处理,例如:仅在上班时间给用户推送消息.本文记录调用免费API查询全年工作日.周末.法定节假日.节假日调休补班数 ...

  3. PHP 判断当前日期是否是法定节假日或者休息日 (原)

    //判断日期是不是节假日或者双休日接口 @param time [时间(时间戳或者Y-m-d都可)] public function get_type_by_date(){ $t = $_GET['t ...

  4. PHP 判断当前日期是否是法定节假日或者休息日

    1.代码如下 $date = date("Ymd",time()); $url = "http://api.goseek.cn/Tools/holiday?date=&q ...

  5. Python-获取法定节假日

    获取公共节假日的接口,http://www.easybots.cn/holiday_api.net, 具体代码如下: # -*- coding:utf-8 -*- import json import ...

  6. 判断日期是否为法定节假日的API接口与示例函数

    需要判定某日期是否为法定节假日,由于国家的节假日每年都在变动,所以使用接口判定是必要的.可惜的是,这样的接口并不多,在此汇总三个: http://tool.bitefu.net/jiari/ http ...

  7. Mac添加中国法定节假日安排

    最近中秋.国庆临近,当大家开始抢票才反应过来,原来假日已然临近,打开mac日历,发现并没有标注节假日安排,发现了这篇文章,写了这篇读后感. 上面的文章介绍使用了两种在苹果系列设备设置中国节假日的方式: ...

  8. vue js moment.js 过滤了双休日和法定节假日

    源码:注!原创的!!!! <template> <div id="DATE"> <ul class="dateForm" @cha ...

  9. ThinkPHP中如何获取指定日期后工作日的具体日期

    思路: 1.获取到查询年份内所有工作日数据数组2.获取到查询开始日期在工作日的索引3.计算需查询日期索引4.获得查询日期 /*创建日期类型记录表格*/ CREATE TABLE `tb_workday ...

随机推荐

  1. Catalan Number-卡特兰数入门

    卡特兰数 首先,我们设f(n)=序列个数为n的出栈序列种数.同时,我们假定,从开始到栈第一次出到空为止,这段过程中第一个出栈的序数是k.特别地,如果栈直到整个过程结束时才空,则k=n. 令h(0)=1 ...

  2. resize([[data],fn]) 当调整浏览器窗口的大小时,发生 resize 事件。

    resize([[data],fn]) 概述 当调整浏览器窗口的大小时,发生 resize 事件.   参数 fnFunctionV1.0 在每一个匹配元素的resize事件中绑定的处理函数.直线电机 ...

  3. Material icons 全图标一览

    Material icons 全图标一览 2018年12月17日 16:52:55 boywcx 阅读数 3090   版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog. ...

  4. JAVA中的getBytes()方法

    在Java中,String的getBytes()方法是得到一个操作系统默认的编码格式的字节数组.这个表示在不同情况下,返回的东西不一样! String.getBytes(String decode)方 ...

  5. C语言学习笔记9-指针

    1.指针基础 NULL为预处理器变量,是从C继承下来的,该变量在cstdlib头文件中定义 2.指针函数与函数指针 3.指针数组与数组指针 4.

  6. Try-Catch-Finally代码块中的return

    测试类的原型是这样子的 public class TryCatchFinallyToReturn { public static void main(String[] args) { System.o ...

  7. C# http请求工具类

    /// <summary> /// Http请求操作类之HttpWebRequest /// </summary> public class HttpHelper { #reg ...

  8. 基于nodejs将mongodb的数据实时同步到elasticsearch

    一.前言 因公司需要选用elasticsearch做全文检索,持久化存储选用的是mongodb,但是希望mongodb里面的数据发生改变可以实时同步到elasticsearch上,一开始主要使用ela ...

  9. JavaWeb_(Spring框架)整合Mybatis加入事务操作数据库

    整合Mybatis a)导包: i.Spring:基本包.aop.aspects.jdbc.tx.test: ii.Mybatis:mybatis-3.4.6 iii.整合包:mybatis-spri ...

  10. 【ElasticSearch+NetCore 第二篇】Nest封装

    using Elasticsearch.Net; using Nest; using System; using System.Collections.Generic; using System.Li ...