Calculating Business Hours






1.33/5 (8 votes)
Jul 11, 2007
2 min read

66104

1133
An article on how to calculate business hours between two dates
Introduction
I was recently asked how many business hours/minutes are between two given dates. I thought the work of finding out would not be so heavy, but it was. In this sample application, I will calculate it with a hard-coded working day range from 8 am. to 5 pm. Holidays are not observed yet.
How many days are between these dates?
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;
}
Ok, so far so good. Now that we have the number of working days, let us calculate the hours.
The first and last day in the date range are "special" days
We can calculate each day with 9 hours per day (predefined range), but not the first and the last day. Let's start calculating seconds for the first day:
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;
}
Ok, now the same with the last day:
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;
}
All together now
Ready. Now we have all of the time values we need. If we put all this together, we get a function with three parameters.
- Parameter 1:
dtStart
is our start date and time value, e.g. 06/20/2007 06:00:00 am - Parameter 2:
dtEnd
is our end date and time value, e.g. 07/14/2007 05:00:00 pm - Parameter 3:
bIsUTCTime
is set to TRUE when Parameters 1 and 2 are UTC time values
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;
}
That's it! I hope you'll find it useful. Please let me know about bugs and other problems if you find any. Enjoy!
Implementation notes
To implement this function into your application, add it and include the following files with your project:
- RPCalcBusinessHours.cpp
- RPCalcBusinessHour.h
The sample project was compiled under VS6 and has been tested on Windows XP. It will not work with versions earlier than Windows NT Workstation 3.5.
Usage
This software is released into the public domain. You are free to use it in any way you like, except that you may not sell this source code. If you modify it or extend it, please consider posting the new code here for everyone to share. This software is provided "as is" with no expressed or implied warranty. I accept no liability for any damage or loss of business that this software may cause.
History
- Version 1.0: 07/11/2007 - Initial release