前段時間公司內部正好在開發一款Flow的辦公系統,涉及到計算請假小時數計算的功能。在網上查了下資料發現很多類似的方法寫的都不是很全面,只是一個大致的思路而已很難直接拿來就用。所以我將這個比較算成熟的方法貼出來以防自己不時之需並且和大家分享。
需求描述:
1、上班時間:08:30分 下班時間:17:30分
2、中午休息時間11:30分~12:30分(不計算小時數)
3、雙休日、國定假日排除掉。
4、雙休日調休上班的也需要計算小時數
設計思路:
1、創建一張節假日表【Vacation】
2、字段: VacationDate、Is_Vacation(假日/工作)、remarks。
3、目的:用來設置【國定假日】 和 【調休上班】的日期。
好一切准備就緒,直接上代碼:
/// </summary>
/// <param name="date"> 時間 </param>
/// <returns> true:工作 | flase:休息 </returns>
private bool IsWorkDay(DateTime date)
{
try
{
//讀取數據庫中【 Vacation】表中的所有數據,返回一個Datatable等等...
//我這里采用的是內存操作Dictionary,因為一般這種節假日都是固定不變的,不需要每次都取訪問數據查詢一遍。
//Dictionary<string, Vacation> m_simVacationData = newDictionary<string, SimVacation>();
//利用Datatable的值循環給 m_simVacationData 賦值。
}
catch (Exception)
{
//拋出異常
}
string DateKey = date;//日期值:“2012-08-01”
bool b_wokrdate = true;
//星期天並且不屬於節假日和調休上班
if (date.DayOfWeek == System.DayOfWeek.Sunday && !m_simVacationData.ContainsKey(DateKey))
return false;
//星期六並且不屬於節假日和調休上班
else if (date.DayOfWeek == System.DayOfWeek.Saturday && !m_simVacationData.ContainsKey(DateKey))
return false;
else if (m_simVacationData.ContainsKey(DateKey))//屬於節假日或調休
{
if (m_simVacationData[DateKey].Is_Vacation)//Is_Vacation=true(節假日) Is_Vacation=false(調休上班)
{
return false;
}
}
return b_wokrdate;
}
///<summary>
/// 計算請假的小時數
///</summary>
///<param name="dtStart">休假開始日期/時間</param>
///<param name="dtEnd">休假結束日期/時間</param>
publicint GetLeaveDay(DateTime dtStart, DateTime dtEnd)
{
DateTime dtFirstDayGoToWork = new DateTime(dtStart.Year,dtStart.Month,dtStart.Day,8,30,0);//請假第一天的上班時間
DateTime dtFirstDayGoOffWork = new DateTime(dtStart.Year,dtStart.Month,dtStart.Day,17,30,0);//請假第一天的下班時間
DateTime dtLastDayGoToWork = new DateTime(dtEnd.Year,dtEnd.Month,dtEnd.Day,8,30,0);//請假最后一天的上班時間
DateTime dtLastDayGoOffWork = new DateTime(dtEnd.Year,dtEnd.Month,dtEnd.Day,17,30,0);//請假最后一天的下班時間
DateTime dtFirstDayRestStart =new DateTime(dtStart.Year,dtStart.Month,dtStart.Day,11,30,0);//請假第一天的午休開始時間
DateTime dtFirstDayRestEnd = new DateTime(dtStart.Year,dtStart.Month,dtStart.Day,12,30,0);//請假第一天的午休結束時間
DateTime dtLastDayRestStart = new DateTime(dtEnd.Year,dtEnd.Month,dtEnd.Day,11,30,0);//請假最后一天的午休開始時間
DateTime dtLastDayRestEnd = new DateTime(dtEnd.Year,dtEnd.Month,dtEnd.Day,12,30,0);//請假最后一天的午休結束時間
//如果開始請假時間早於上班時間或者結束請假時間晚於下班時間,者需要重置時間
if (!IsWorkDay(dtStart) && !IsWorkDay(dtEnd))
return 0;
if (dtStart >= dtFirstDayGoOffWork && dtEnd <= dtLastDayGoToWork && (dtEnd - dtStart).TotalDays < 1)
return 0;
if (dtStart >= dtFirstDayGoOffWork && !IsWorkDay(dtEnd) && (dtEnd - dtStart).TotalDays < 1)
return 0;
if (dtStart < dtFirstDayGoToWork)//早於上班時間
dtStart = dtFirstDayGoToWork;
if (dtStart >= dtFirstDayGoOffWork)//晚於下班時間
{
while (dtStart < dtEnd)
{
dtStart = new DateTime(dtStart.AddDays(1).Year, dtStart.AddDays(1).Month, dtStart.AddDays(1).Day, 8, 30, 0);
if (IsWorkDay(dtStart))
{
dtFirstDayGoToWork = new DateTime(dtStart.Year, dtStart.Month, dtStart.Day, 8, 30, 0);//請假第一天的上班時間
dtFirstDayGoOffWork = new DateTime(dtStart.Year, dtStart.Month, dtStart.Day, 17, 30, 0);//請假第一天的下班時間
dtFirstDayRestStart = new DateTime(dtStart.Year, dtStart.Month, dtStart.Day, 11, 30, 0);//請假第一天的午休開始時間
dtFirstDayRestEnd = new DateTime(dtStart.Year, dtStart.Month, dtStart.Day, 12, 30, 0);//請假第一天的午休結束時間
break;
}
}
}
if (dtEnd > dtLastDayGoOffWork)//晚於下班時間
dtEnd = dtLastDayGoOffWork;
if (dtEnd <= dtLastDayGoToWork)//早於上班時間
{
while (dtEnd > dtStart)
{
dtEnd = new DateTime(dtEnd.AddDays(-1).Year, dtEnd.AddDays(-1).Month, dtEnd.AddDays(-1).Day, 17, 30, 0);
if (IsWorkDay(dtEnd))//
{
dtLastDayGoToWork = new DateTime(dtEnd.Year, dtEnd.Month, dtEnd.Day, 8, 30, 0);//請假最后一天的上班時間
dtLastDayGoOffWork = new DateTime(dtEnd.Year, dtEnd.Month, dtEnd.Day, 17, 30, 0);//請假最后一天的下班時間
dtLastDayRestStart = new DateTime(dtEnd.Year, dtEnd.Month, dtEnd.Day, 11, 30, 0);//請假最后一天的午休開始時間
dtLastDayRestEnd = new DateTime(dtEnd.Year, dtEnd.Month, dtEnd.Day, 12, 30, 0);//請假最后一天的午休結束時間
break;
}
}
}
//計算請假第一天和最后一天的小時合計數並換算成分鍾數
double iSumMinute = dtFirstDayGoOffWork.Subtract(dtStart).TotalMinutes + dtEnd.Subtract(dtLastDayGoToWork).TotalMinutes;//計算獲得剩余的分鍾數
if (dtStart > dtFirstDayRestStart && dtStart < dtFirstDayRestEnd)
{//開始休假時間正好是在午休時間內的,需要扣除掉
iSumMinute = iSumMinute - dtFirstDayRestEnd.Subtract(dtStart).Minutes;
}
if (dtStart < dtFirstDayRestStart)
{//如果是在午休前開始休假的就自動減去午休的60分鍾
iSumMinute = iSumMinute - 60;
}
if (dtEnd > dtLastDayRestStart && dtEnd < dtLastDayRestEnd)
{//如果結束休假是在午休時間內的,例如“請假截止日是1月31日 12:00分”的話那休假時間計算只到 11:30分為止。
iSumMinute = iSumMinute - dtEnd.Subtract(dtLastDayRestStart).Minutes;
}
if (dtEnd > dtLastDayRestEnd)
{//如果是在午休后結束請假的就自動減去午休的60分鍾
iSumMinute = iSumMinute - 60;
}
int leaveday = 0;//實際請假的天數
double countday = 0;//獲取兩個日期間的總天數
DateTime tempDate = dtStart;//臨時參數
while (tempDate < dtEnd)
{
countday++;
tempDate = new DateTime(tempDate.AddDays(1).Year, tempDate.AddDays(1).Month, tempDate.AddDays(1).Day , 0, 0, 0);
}
//循環用來扣除雙休日、法定假日 和 添加調休上班
for (int i = 0; i < countday; i++)
{
DateTime tempdt = dtStart.Date.AddDays(i);
if (IsWorkDay(tempdt))
leaveday++;
}
//去掉請假第一天和請假的最后一天,其余時間全部已8小時計算。
//SumMinute/60: 獨立計算 請假第一天和請假最后一天總歸請了多少小時的假
double doubleSumHours = ((leaveday - 2) * 8) + iSumMinute / 60;
int intSumHours=Convert.ToInt32(doubleSumHours);
if (doubleSumHours > intSumHours)//如果請假時間不足1小時話自動算作1小時
intSumHours++;
return intSumHours;
}