Try using the BusinessHours.diff(String, Datetime, Datetime) method.
Returns the difference between a start and end Datetime based on a specific set of business hours.
NOTE : The following examples assume that the current user is in the the same timezone as the BusinessHours. If not, you will need to correct via GMT/UTC.
// Get the default business hours
BusinessHours bh = [SELECT Id, MondayStartTime, MondayEndTime, TuesdayStartTime, TuesdayEndTime, TimeZoneSidKey FROM BusinessHours WHERE IsDefault=true];
Datetime inTime = Datetime.newInstance(2014, 1, 1, 19, 0, 0);
System.assert(!BusinessHours.isWithin(bh.id, inTime));
Datetime outTime = Datetime.newInstance(2014, 1, 2, 7, 0, 0);
System.assert(!BusinessHours.isWithin(bh.id, outTime), outTime.format() + ' GMT: '+ outTime.timeGMT()+ ' expected to be out of business hours' + bh);
long businessMillisecondsDiff = BusinessHours.diff(bh.Id, inTime, outTime);
decimal businessHoursDiff = businessMillisecondsDiff / (1000.0*60.0*60.0);
// The get the time difference and convert from milliseconds to hours.
decimal totalHoursDiff = (outTime.getTime() - inTime.getTime()) / (1000.0*60.0*60.0);
System.assertEquals(12.0, totalHoursDiff);
decimal outOfBusinessHours = totalHoursDiff - businessHoursDiff;
System.debug('totalHoursDiff:' + totalHoursDiff +
'\n businessHoursDiff: ' + businessHoursDiff +
'\n outOfBusinessHours:' + outOfBusinessHours);
totalHoursDiff:12
businessHoursDiff: 0E+3
outOfBusinessHours:12
The following separate test also works:
BusinessHours bh = [SELECT Id, MondayStartTime, MondayEndTime, TuesdayStartTime, TuesdayEndTime, TimeZoneSidKey FROM BusinessHours WHERE IsDefault=true];
Datetime inTime = Datetime.newInstance(2014, 1, 6, 11, 0, 0);
System.assert(BusinessHours.isWithin(bh.id, inTime));
Datetime outTime = Datetime.newInstance(2014, 1, 6, 20, 0, 0);
System.assert(!BusinessHours.isWithin(bh.id, outTime), outTime.format() + ' GMT: '+ outTime.timeGMT()+ ' expected to be out of business hours' + bh);
long businessMillisecondsDiff = BusinessHours.diff(bh.Id, inTime, outTime);
decimal businessHoursDiff = businessMillisecondsDiff / (1000.0*60.0*60.0);
// The get the time difference and convert from milliseconds to hours.
decimal totalHoursDiff = (outTime.getTime() - inTime.getTime()) / (1000.0*60.0*60.0);
System.assertEquals(9.0, totalHoursDiff);
decimal outOfBusinessHours = totalHoursDiff - businessHoursDiff;
System.debug('totalHoursDiff:' + totalHoursDiff +
'\n businessHoursDiff: ' + businessHoursDiff +
'\n outOfBusinessHours:' + outOfBusinessHours);
totalHoursDiff:9
businessHoursDiff: 7
outOfBusinessHours:2