1

Hello I need help understanding how business hours difference is calculated with the Apex class. The documentation is rather poor and doesn't explain the input parameters assumptions. I found one post on a forum saying local time is assumed but it doesn't seem to be the case. Could someone help me to understand where I make wrong assumptions?

I have an org with Business Hours set 8AM-6PM. The org's time zone is set to Europe/London and till last Saturday of October it's tuned to British Summer Time (GMT+1).

If I submit a case at 17:15 BST and I want to check the minute difference between 18:00 BST the following day I would expect to see 645 minutes. But the Business Hours class returns 600.

//Datetime submitTime = DateTime.now(); simulate submitting case at 17:15 BST
Datetime submitTime = DateTime.newInstance(2018,10,17,17,15,0);//returns GMT 16:15

//move GMT time to London's local time 
Timezone londonTZ = Timezone.getTimeZone('Europe/London');
submitTime = submitTime.addSeconds(londonTZ.getOffset(submitTime)/1000); 
//now GMT has moved to BST 16:15->17:15
System.debug('=====================  FINAL submitTime='+submitTime); 

//construct end of working day the next day
Time endOfBusinessTime = Time.newInstance(18, 0, 0, 0); //UTC is assumed
Datetime targetTime = Datetime.newInstance(date.newInstance(2018,10,18), endOfBusinessTime); 
//returns GMT time 17:00

//move GMT time to London's local time 
targetTime =  targetTime.addSeconds(londonTZ.getOffset(targetTime)/1000);//17GMT->18BST
System.debug('=====================  FINAL targetTime='+targetTime );


// business hours are 8:00 -16:00 and org is set in BST timezone
BusinessHours defaultBH = [SELECT Id FROM BusinessHours WHERE IsDefault = true];
Long inputMillisecs =  BusinessHours.diff(defaultBH.Id, submitTime, targetTime);
Long total_duration_in_seconds = (inputMillisecs/1000).intValue(); 
System.debug('===================== diff in working minutes ='+total_duration_in_seconds/60);  //this prints 600 not 645

1 Answer 1

3

All data is always stored in GMT (now referred to as UTC) regardless of what the local time is. Changing your data to local time to work with it can be dangerous when it comes to Daylight Savings Times because those dates change from year to year. They can even change during a during a shift which is especially problematic to resolve.

You can generally expect your Apex to run in the context of your Org's Default Time Zone. You didn't say where your org is located, so that could potentially affect your calculations.

One of the things I would suggest you look at that could be affecting these calculations are case assignment and workflow rules (are the cases being assigned synchronously or asynchronously?). I suspect the reason you're getting 600 (10 hrs) is the case may not have been assigned until the following day since it did not come in until 15 minutes before the close of business. There are many rules that can potentially affect how cases are affected in terms of entitlements and business hours. You'll find some relevant documentation under How Business Hours Work in Entitlement Management. It may not be especially helpful to you for this specific question, bit it could provide you with insight that will lead you someplace else.

I also recommend this KB article Dynamically assign Business Hours. I wouldn't expect your org to be doing this, but one never knows.

EDIT

I reviewed the documentation on the method you've used in your testing, and it left me with the impression that it may be intended to capture "hours between business days" rather than "hours and minutes between business days". I recommend you try the following:

Time endOfBusinessTime = Time.newInstance(18, 0, 0, 0); //UTC is assumed
Datetime targetEOBTime = Datetime.newInstance(date.newInstance(2018,10,18), endOfBusinessTime);
Datetime submitTime = DateTime.newInstance(2018,10,17,17,15,0);//returns GMT 16:15
Long intervalMilliseconds = 645000;
BusinessHours defaultBH = [SELECT Id FROM BusinessHours WHERE IsDefault = true];
DateTime targetTime = submitTime.add(businessHoursId, startDate, intervalMilliseconds);

If your business hours are taking the change of Daylight Savings Time into account, this should result in targetTime = targetEOBTime and you should be able to assert those results.

If it doesn't produce the expected results, then there may be an issue with Daylight Savings Time not having been set for 2018 in your Org's settings. I'd then recommend you try the same for 2017 and see if you get the same results.

If 2017 works using this method and 2018 does not, I would file a case with Salesforce support as you should not need to enter daylight savings times into your org.

2
  • Thank you for taking time to reply. The data is not stored, no assignments or entitlements. We are talking pure Apex in memory validation that takes current time and user's chosen date (end of business time). I mentioned the org is set up with Europe/London and we are currently having summer time. The test user is located in the same timezone but I think the code accounts for cases when user in different time zone are submitting cases that will be worked on in London't time.
    – user682217
    Commented Oct 17, 2018 at 18:32
  • See my edited answer. I recommend you use GMT for all the methods. The runAs user should not matter if you use GMT and I agree with you that the datetimes were created in the proper time zones, so again not affected by the runAs user.
    – crmprogdev
    Commented Oct 18, 2018 at 15:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .