计算工作时间






1.33/5 (8投票s)
2007年7月11日
2分钟阅读

66716

1171
关于如何计算两个日期之间工作时间的文章
引言
我最近被问到如何计算两个给定日期之间的工作时长(小时/分钟)。我原本以为这不会太复杂,但实际上却不然。在这个示例应用程序中,我将使用硬编码的工作时间范围,从上午 8 点到下午 5 点来计算。目前尚未考虑节假日。
这两个日期之间有多少天?
int GetBusinessDays(CTime ctStart, CTime ctEnd)
{
CTimeSpan ctp(ctEnd - ctStart);
int iDays = ctp.GetDays() + 1;
int iWeeks = iDays / 7;
int iBusDays = iWeeks * 5;
int iRem = iDays % 7;
while (iRem > 0)
{ // no sunday, no saturday
if ((ctStart.GetDayOfWeek() != 1) && (ctStart.GetDayOfWeek() != 7))
{
iBusDays++;
} ctStart += CTimeSpan(1,0,0,0); // add a day
iRem--;
}
return iBusDays;
}
好的,到目前为止一切顺利。现在我们已经有了工作天数,让我们来计算小时数。
日期范围内的第一天和最后一天是“特殊”的日子
我们可以计算每天 9 个小时(预定义的范围),但对于第一天和最后一天则不行。让我们开始计算第一天的秒数
DWORD CorrectFirstDayTime(CTime ctStart, CTime ctMaxTime, CTime ctMinTime)
{
DWORD daysec = 0;
if (ctMaxTime < ctStart) // start time is after max time
return 0; // zero seconds for the first day
if ((ctStart.GetDayOfWeek() == 1) || (ctStart.GetDayOfWeek() == 7))
return 0; // zero seconds for weekend
if (ctStart < ctMinTime) // start time is befor min time
ctStart = ctMinTime; // set start time to min time
// calulate seconds of this day
CTimeSpan ctSpan(ctMaxTime - ctStart);
daysec =
(ctSpan.GetDays() * 24 * 60 * 60) + (ctSpan.GetHours() * 60 * 60) +
(ctSpan.GetMinutes() * 60) + ctSpan.GetSeconds();
return daysec;
}
好的,现在用同样的方法处理最后一天
DWORD CorrectLastDayTime(CTime ctEnd, CTime ctMaxTime, CTime ctMinTime)
{
DWORD daysec = 0;
if (ctMinTime > ctEnd) // end time is befor min time
return 0; // zero seconds for the end day
if ((ctEnd.GetDayOfWeek() == 1) || (ctEnd.GetDayOfWeek() == 7))
return 0;
if (ctEnd > ctMaxTime) // end time is afer max time
ctEnd = ctMaxTime; // set end time to max time
// calulate seconds of this day
CTimeSpan ctSpan(ctEnd - ctMinTime);
daysec =
(ctSpan.GetDays() * 24 * 60 * 60) + (ctSpan.GetHours() * 60 * 60) +
(ctSpan.GetMinutes() * 60) + ctSpan.GetSeconds();
return daysec;
}
现在全部加起来
准备好了。现在我们有了所有需要的时间值。如果我们把这些都放在一起,我们就可以得到一个带有三个参数的函数。
- 参数 1:
dtStart
是我们的开始日期和时间值,例如 2007/06/20 06:00:00 am - 参数 2:
dtEnd
是我们的结束日期和时间值,例如 2007/07/14 05:00:00 pm - 参数 3:
bIsUTCTime
当参数 1 和 2 是 UTC 时间值时,设置为 TRUE
double CalculateBusinessMinutes(CTime dtStart, CTime dtEnd, BOOL bIsUTCTime)
{
// initialze our return value
double OverAllMinutes = 0.0;
// start time must be less than end time
if (dtStart > dtEnd)
return OverAllMinutes;
if (bIsUTCTime)
{
// convert time from UTC to local time
SYSTEMTIME ttStart;
SYSTEMTIME ttEnd;
SYSTEMTIME ttStartLocal;
SYSTEMTIME ttEndLocal;
dtStart.GetAsSystemTime(ttStart);
dtEnd.GetAsSystemTime(ttEnd);
SystemTimeToTzSpecificLocalTime(NULL, &ttStart, &ttStartLocal);
SystemTimeToTzSpecificLocalTime(NULL, &ttEnd, &ttEndLocal);
dtStart = ttStartLocal;
dtEnd = ttEndLocal;
}
// initialize our temp times with midnight values
CTime ctTempStart(dtStart.GetYear(),
dtStart.GetMonth(), dtStart.GetDay(), 0, 0, 0);
CTime ctTempEnd(dtEnd.GetYear(),
dtEnd.GetMonth(), dtEnd.GetDay(), 0, 0, 0);
// check if startdate and enddate are the same day
BOOL bSameDay = (ctTempStart == ctTempEnd);
// calculate the business days between the dates
int iBusinessDays = GetBusinessDays(ctTempStart, ctTempEnd);
// now add the time values to our temp times
ctTempStart += CTimeSpan(0, dtStart.GetHour(), dtStart.GetMinute(), 0);
ctTempEnd += CTimeSpan(0, dtEnd.GetHour(), dtEnd.GetMinute(), 0);
// set our workingday time range and correct the first day
CTime ctMaxTime(ctTempStart.GetYear(),
ctTempStart.GetMonth(), ctTempStart.GetDay(), 17, 0, 0);
CTime ctMinTime(ctTempStart.GetYear(),
ctTempStart.GetMonth(), ctTempStart.GetDay(), 8, 0, 0);
DWORD FirstDaySec =
CorrectFirstDayTime(ctTempStart, ctMaxTime, ctMinTime);
// set our workingday time range and correct the last day
CTime ctMaxTime1(ctTempEnd.GetYear(),
ctTempEnd.GetMonth(), ctTempEnd.GetDay(), 17, 0, 0);
CTime ctMinTime1(ctTempEnd.GetYear(),
ctTempEnd.GetMonth(), ctTempEnd.GetDay(), 8, 0, 0);
DWORD LastDaySec = CorrectLastDayTime(ctTempEnd, ctMaxTime1, ctMinTime1);
DWORD OverAllSec = 0;
// now sum-up all values
if (bSameDay)
{
if (iBusinessDays != 0)
{
CTimeSpan cts(ctMaxTime - ctMinTime);
DWORD dwBusinessDaySeconds =
(cts.GetDays() * 24 * 60 * 60) + (cts.GetHours() * 60 * 60) +
(cts.GetMinutes() * 60) + cts.GetSeconds();
OverAllSec = FirstDaySec + LastDaySec - dwBusinessDaySeconds;
}
}
else
{
if (iBusinessDays > 1)
OverAllSec =
((iBusinessDays - 2) * 9 * 60 * 60) + FirstDaySec + LastDaySec;
}
OverAllMinutes = OverAllSec / 60;
return OverAllMinutes;
}
就这样!我希望它对您有所帮助。如果您发现任何错误或其他问题,请告诉我。祝您使用愉快!
实施说明
要在您的应用程序中实现此函数,请添加它并包含以下文件到您的项目中
- RPCalcBusinessHours.cpp
- RPCalcBusinessHour.h
该示例项目是在 VS6 下编译的,并在 Windows XP 上进行了测试。它不能在 Windows NT Workstation 3.5 之前的版本上运行。
用法
此软件以公共领域形式发布。您可以以任何您喜欢的方式自由使用它,但不得出售此源代码。如果您对其进行修改或扩展,请考虑在此处发布新代码供大家共享。此软件按“原样”提供,不提供任何明示或暗示的保证。我对因该软件造成的任何损害或业务损失不承担任何责任。
历史
- 版本 1.0:2007/11/07 - 初始发布