Reputation: 8034
For an issue tracking system I need to calculate the response time for a request. The timer for response time should only be running during business hours. What algorithm/library should I use for this task? (Sure thing, I know about Joda-Time or ObjectLab Kit, but couldn't find anything helping with my task. Am I missing something?)
Example:
The method may look something like:
DateTime calculateResponseTime(DateTime issueReportedAt)
I'll give some possible inputs and results as example:
Upvotes: 13
Views: 5536
Reputation: 2175
Below code does solve the this problem
public static Date addBusinessHours(Calendar startDate, int hours, int workingHourStart, int workingHourEnd){
System.out.println("Entering: Date Time " + startDate.getTime() + " | Remaining Hours: "+ hours + " | Working hours ("+workingHourStart+"-"+workingHourEnd+")");
if(hours == 0){
return startDate.getTime();
}
int hourOfDay = startDate.get(Calendar.HOUR_OF_DAY);
if(startDate.get(Calendar.MINUTE) > 0){
hourOfDay = hourOfDay +1;
}
int dayOfWeek = startDate.get(Calendar.DAY_OF_WEEK);
if(dayOfWeek == Calendar.SATURDAY){
startDate.add(Calendar.DATE, 2);
startDate.set(Calendar.HOUR_OF_DAY, workingHourStart);
startDate.set(Calendar.MINUTE, 0);
startDate.set(Calendar.SECOND, 0);
addBusinessHours(startDate, hours, workingHourStart, workingHourEnd);
}
if(dayOfWeek == Calendar.SUNDAY){
startDate.add(Calendar.DATE, 1);
startDate.set(Calendar.HOUR_OF_DAY, workingHourStart);
startDate.set(Calendar.MINUTE, 0);
startDate.set(Calendar.SECOND, 0);
addBusinessHours(startDate, hours, workingHourStart, workingHourEnd);
}
if(dayOfWeek != Calendar.SATURDAY && dayOfWeek != Calendar.SUNDAY){
if(hourOfDay < workingHourStart){
startDate.set(Calendar.HOUR_OF_DAY, workingHourStart);
startDate.set(Calendar.MINUTE, 0);
startDate.set(Calendar.SECOND, 0);
hourOfDay = startDate.get(Calendar.HOUR_OF_DAY);
dayOfWeek = startDate.get(Calendar.DAY_OF_WEEK);
addBusinessHours(startDate, hours, workingHourStart, workingHourEnd);
}
else if(hourOfDay >= workingHourEnd){
startDate.add(Calendar.DATE, 1);
startDate.set(Calendar.HOUR_OF_DAY, workingHourStart);
startDate.set(Calendar.MINUTE, 0);
startDate.set(Calendar.SECOND, 0);
hourOfDay = startDate.get(Calendar.HOUR_OF_DAY);
dayOfWeek = startDate.get(Calendar.DAY_OF_WEEK);
addBusinessHours(startDate, hours, workingHourStart, workingHourEnd);
}
else if(hourOfDay >= workingHourStart && hourOfDay < workingHourEnd){
if(hours+hourOfDay <= workingHourEnd){
startDate.add(Calendar.HOUR_OF_DAY, hours);
return startDate.getTime();
}else{
//System.out.println("¤¤" + startDate.getTime() );
startDate.add(Calendar.DATE, 1);
//System.out.println("¤¤" + startDate.getTime() );
startDate.set(Calendar.HOUR_OF_DAY, workingHourStart);
startDate.set(Calendar.MINUTE, 0);
startDate.set(Calendar.SECOND, 0);
//System.out.println("¤¤" + startDate.getTime() );
System.out.println("##"+hours+ "##"+ workingHourEnd + "##" + hourOfDay);
int remaining_hours = hours - (workingHourEnd - hourOfDay);
addBusinessHours(startDate, remaining_hours, workingHourStart, workingHourEnd);
}
}
}
return startDate.getTime();
}
Upvotes: 0
Reputation: 426
You need to add an extra if case to the normalization part from Anils answer because if the issue is reported on a Friday 10:00 AM and the responseHours is 10, than in the next recursive call the issueReportedAt will be Friday 10 PM, witch will be normalized to Saturday 9:00 PM, witch is invalid as well.
if (hourOfDay >= WorkingHours.TO_HOUR && dayOfWeek == Calendar.FRIDAY) {
responseTime.add(Calendar.DATE, 3);
responseTime.set(Calendar.HOUR_OF_DAY, WorkingHours.FROM_HOUR);
responseTime.set(Calendar.MINUTE, WorkingHours.FROM_MINUTE);
}
Upvotes: 0
Reputation: 21
I think what Oleg was suggesting was taking a look at the way jBPM implements this functionality for inspiration for coding your own solution. Below is my answer borrowing heavily from the source I found by doing a Google Code Search.
It does not take into account holidays, but I will leave that as an exercise for you. May I suggest using a web service to annually update a restricted date list? Good luck!
int fromHour = 9;
int fromMinute = 0;
int toHour = 17;
int toMinute = 0;
long maxResponseTime = 16;
Date calculateResponseTime(Date issueReportedAt, long responseHours) {
Date end = null;
Calendar responseTime = Calendar.getInstance();
responseTime.setTime(issueReportedAt);
int hourOfDay = responseTime.get(Calendar.HOUR_OF_DAY);
int dayOfWeek = responseTime.get(Calendar.DAY_OF_WEEK);
if (hourOfDay < fromHour) {
responseTime.set(Calendar.HOUR, fromHour);
}
if (hourOfDay >= toHour || dayOfWeek == 1) {
responseTime.add(Calendar.DATE, 1);
responseTime.set(Calendar.HOUR_OF_DAY, fromHour);
responseTime.set(Calendar.MINUTE, fromMinute);
} else if (dayOfWeek == 7) {
responseTime.add(Calendar.DATE, 2);
responseTime.set(Calendar.HOUR_OF_DAY, fromHour);
responseTime.set(Calendar.MINUTE, fromMinute);
}
int hour = responseTime.get(Calendar.HOUR_OF_DAY);
int minute = responseTime.get(Calendar.MINUTE);
long dateMilliseconds = ((hour * 60) + minute) * 60 * 1000;
long dayPartEndMilleseconds = ((toHour * 60) + toMinute) * 60 * 1000;
long millisecondsInThisDayPart = dayPartEndMilleseconds
- dateMilliseconds;
long durationMilliseconds = responseHours * 60 * 60 * 1000;
if (durationMilliseconds < millisecondsInThisDayPart) {
end = new Date(responseTime.getTimeInMillis()
+ durationMilliseconds);
} else {
long remainder = (durationMilliseconds - millisecondsInThisDayPart) / 60 / 60 / 1000;
Date dayPartEndDate = new Date(responseTime.getTimeInMillis()
+ durationMilliseconds);
responseTime.setTime(dayPartEndDate);
end = calculateResponseTime(responseTime.getTime(), remainder);
}
return end;
}
@Test
public void testCalculateResponseTime() {
Calendar issueReportedAt = Calendar.getInstance();
Calendar expectedResponseTime = Calendar.getInstance();
issueReportedAt.set(2011, 8, 19, 13, 0, 0);
expectedResponseTime.set(2011, 8, 21, 13, 0, 0);
assertTrue(expectedResponseTime.getTime().equals(
calculateResponseTime(issueReportedAt.getTime(),
maxResponseTime)));
issueReportedAt.set(2011, 8, 19, 18, 5, 0);
expectedResponseTime.set(2011, 8, 22, 9, 0, 0);
assertTrue(expectedResponseTime.getTime().equals(
calculateResponseTime(issueReportedAt.getTime(),
maxResponseTime)));
issueReportedAt.set(2011, 8, 23, 14, 0, 0);
expectedResponseTime.set(2011, 8, 27, 14, 0, 0);
assertTrue(expectedResponseTime.getTime().equals(
calculateResponseTime(issueReportedAt.getTime(),
maxResponseTime)));
}
Upvotes: 2
Reputation: 21162
You may take a look on the jBPM business calendar.
Another library allows you configure bank holidays but it doesn't have a notion of business hours.
Upvotes: 3