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

一、开发背景:

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

二、定义:

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

三、实践:

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

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

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

    

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

    

  具体代码:

public class HolidayHelper
{
#region 字段属性
private static object _syncObj = new object();
private static HolidayHelper _instance { get; set; }
private static List<DateModel> cacheDateList { get; set; }
private HolidayHelper() { }
/// <summary>
/// 获得单例对象,使用懒汉式(双重锁定)
/// </summary>
/// <returns></returns>
public static HolidayHelper GetInstance()
{
if (_instance == null)
{
lock (_syncObj)
{
if (_instance == null)
{
_instance = new HolidayHelper();
}
}
}
return _instance;
}
#endregion #region 私有方法
/// <summary>
/// 读取文件
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
private string GetFileContent(string filePath)
{
string result = "";
if (File.Exists(filePath))
{
result = File.ReadAllText(filePath);
}
return result;
}
/// <summary>
/// 获取配置的Json文件
/// </summary>
/// <returns>经过反序列化之后的对象集合</returns>
private List<DateModel> GetConfigList()
{
string path = string.Format("{0}/../../Config/holidayConfig.json", System.AppDomain.CurrentDomain.BaseDirectory);
string fileContent = GetFileContent(path);
if (!string.IsNullOrWhiteSpace(fileContent))
{
cacheDateList = Newtonsoft.Json.JsonConvert.DeserializeObject<List<DateModel>>(fileContent);
}
return cacheDateList;
}
/// <summary>
/// 获取指定年份的数据
/// </summary>
/// <param name="year"></param>
/// <returns></returns>
private DateModel GetConfigDataByYear(int year)
{
if (cacheDateList == null)//取配置数据
GetConfigList();
DateModel result = cacheDateList.FirstOrDefault(m => m.Year == year);
return result;
}
/// <summary>
/// 判断是否为工作日
/// </summary>
/// <param name="currDate">要判断的时间</param>
/// <param name="thisYearData">当前的数据</param>
/// <returns></returns>
private bool IsWorkDay(DateTime currDate, DateModel thisYearData)
{
if (currDate.Year != thisYearData.Year)//跨年重新读取数据
{
thisYearData = GetConfigDataByYear(currDate.Year);
}
if (thisYearData.Year > 0)
{
string date = currDate.ToString("MMdd");
int week = (int)currDate.DayOfWeek; if (thisYearData.Work.IndexOf(date) >= 0)
{
return true;
} if (thisYearData.Holiday.IndexOf(date) >= 0)
{
return false;
} if (week != 0 && week != 6)
{
return true;
}
}
return false;
} #endregion #region 公共方法
public void CleraCacheData()
{
if (cacheDateList != null)
{
cacheDateList.Clear();
}
}
/// <summary>
/// 根据传入的工作日天数,获得计算后的日期,可传负数
/// </summary>
/// <param name="day">天数</param>
/// <param name="isContainToday">当天是否算工作日(默认:true)</param>
/// <returns></returns>
public DateTime GetReckonDate(int day, bool isContainToday = true)
{
DateTime currDate = DateTime.Now;
int addDay = day >= 0 ? 1 : -1; if (isContainToday)
currDate = currDate.AddDays(-addDay); DateModel thisYearData = GetConfigDataByYear(currDate.Year);
if (thisYearData.Year > 0)
{
int sumDay = Math.Abs(day);
int workDayNum = 0;
while (workDayNum < sumDay)
{
currDate = currDate.AddDays(addDay);
if (IsWorkDay(currDate, thisYearData))
workDayNum++;
}
}
return currDate;
}
/// <summary>
/// 根据传入的时间,计算工作日天数
/// </summary>
/// <param name="date">带计算的时间</param>
/// <param name="isContainToday">当天是否算工作日(默认:true)</param>
/// <returns></returns>
public int GetWorkDayNum(DateTime date, bool isContainToday = true)
{
var currDate = DateTime.Now; int workDayNum = 0;
int addDay = date.Date > currDate.Date ? 1 : -1; if (isContainToday)
{
currDate = currDate.AddDays(-addDay);
} DateModel thisYearData = GetConfigDataByYear(currDate.Year);
if (thisYearData.Year > 0)
{
bool isEnd = false;
do
{
currDate = currDate.AddDays(addDay);
if (IsWorkDay(currDate, thisYearData))
workDayNum += addDay;
isEnd = addDay > 0 ? (date.Date > currDate.Date) : (date.Date < currDate.Date);
} while (isEnd);
}
return workDayNum;
}
#endregion
} public struct DateModel
{
public int Year { get; set; } public List<string> Work { get; set; } public List<string> Holiday { get; set; }
}

  说明下,法定节假日我是自己用json来配置的,大家可以自己维护,或者做成自己的接口。下面展示下json的格式,这是我自己配置的(2015-2017年),大家可以按照自己的需求来修改。

[
{
"Year": "2015",
"Work": [ "0104", "0215", "0228", "0906", "1010" ],
"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" ]
},
{
"Year": "2016",
"Work": [ "0206", "0214", "0612", "0918", "1008", "1009" ],
"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" ]
},
{
"Year": "2017",
"Work": [ "0122", "0204", "0401", "0527", "0930" ],
"Holiday": [ "0101", "0102", "0127", "0128", "0129", "0130", "0201", "0202", "0501", "0529", "0530", "1001", "1002", "1003", "1004", "1005", "1006" ]
}
] 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. C# 操作文件夹、文件

    Form namespace FileProperties { public partial class Form1 : Form { private string currentFolderPath ...

  2. BZOJ 3566 概率充电器(树形概率DP)

    题面 题目传送门 分析 定义f(i)f(i)f(i)为iii点不被点亮的概率,p(i)p(i)p(i)为iii自己被点亮的概率,p(i,j)p(i,j)p(i,j)表示i−ji-ji−j 这条边联通的 ...

  3. js特殊字符的验证

    // 特殊字符的验证 // 包含特殊字符返回true,不包含特殊字符返回false function checkEspcial(s) { var str=trim(s); //var reg=/< ...

  4. luogu 5354 [Ynoi2017]由乃的OJ LCT+位运算

    如果做过起床困难综合征的话应该很快就能有思路,没做过那道题的话还真是挺费劲的. 我们不知道要带入的值是什么,但是我们可以知道假设带入值得当前位为 $1$ 时这一位在经过位运算后是否为 $1$. 至于这 ...

  5. 使用std::function改善模板的低效性

    泛型编程中,模板会根据传入类型的不同,生成多种实例,相对低效. 模板编程: #include <iostream> using namespace std; //未使用函数包装器 temp ...

  6. 路飞项目-ContentType组件

    ContentType组件 -- 应用 价格策略 常见问题 优惠券 -- 一张表跟多张表建立外键关系的 -- 用法 # 第一步 先生成ForeignKey字段 关联ContentType conten ...

  7. 【概率论】4-2:期望的性质(Properties of Expectation)

    title: [概率论]4-2:期望的性质(Properties of Expectation) categories: - Mathematic - Probability keywords: - ...

  8. Flask 编写一个授权登录验证的模块(二)

    本篇比上一篇多了重定向的功能 #!/usr/bin/env python # -*- coding: utf-8 -*- #python3 import base64 import random im ...

  9. 阿里前端实习生面试总结(两轮技术面+一轮hr面)

    投的蚂蚁金服: 一面(只有13分钟): 1.angular里双向绑定的实现原理: 巴拉巴拉巴拉,这个问题很常见,我提到了$scope.$apply()和$scope.$digest(),面试官问app ...

  10. Linux系统下查找最近修改过的文件

    Linux的终端上,没有windows的搜索那样好用的图形界面工具,但find命令确是很强大的. 比如按名字查找一个文件,可以用 find / -name targetfilename . 唉,如果只 ...