SfSkills Domains Docs GitHub

Home / admin / business-hours-and-holidays

business-hours-and-holidays

Use this skill when creating, deploying, or troubleshooting Salesforce Business Hours and Holidays: the calendars that pause Case escalation rules, entitlement milestones, and Apex BusinessHours math outside working hours.

Open the skill folder on GitHub


Business Hours and Holidays

Activates when an SLA clock has to stop outside working hours. A business-hours calendar is the only thing that makes escalation rules, milestones, and BusinessHours Apex methods count working time instead of wall-clock time, and a holiday only counts once it is attached to a calendar.


Before Starting

Questions to Ask Before Configuring

Ask these before touching Setup; the answers decide the design, and an LLM that skips them produces a calendar that looks right and pauses nothing.

AskWhy it mattersWhat a good answer adds
"Which SLA promise are we making, and to whom: one business day, four working hours, calendar hours?"Fixes whether business time is needed at all and which consumers must read itThe consumer map: escalation entries, milestones, Apex
"Which regions or teams work different hours or observe different holidays?"Each distinct answer is a calendarThe calendar list, each with a time zone and holiday set
"How do we know a Case's region at creation?"Decides the Case.BusinessHoursId rule; if unknowable at creation, the design falls back to the defaultThe before-save Flow logic and its fallback
"Is there any Case type that must be worked round the clock?"Those escalation entries use businessHoursSource = None on purposeDocumented exceptions instead of accidental 24/7
"Who maintains next year's holidays, and when?"Holidays expire; unmaintained calendars silently stop pausingAn owner and a yearly deploy in the release calendar
"Do reports or code need elapsed working time?"Formulas cannot compute it; Apex diff canA decision to build (or not build) the Apex helper

What a proper configuration adds over "just creating business hours": the SLA clock actually stops on weekends and holidays per region, escalation and milestone targets agree with each other, and the yearly holiday update is a reviewed deploy rather than a forgotten Setup task.


Core Concepts

The calendar record

A calendar is a BusinessHours record: name, active flag, default flag, time zone, and a start and end time for each weekday. All users can read BusinessHours through the API even without setup permissions, which is why Apex and Flow can look one up freely. Exactly one calendar is the org default. The Object Reference states the escalation consequence directly: "Escalation rules are run only during these hours", and holidays associated with the calendar suspend both the hours and the escalation rules that use them.

FieldMeaning
NameReferenced by name in escalation rule metadata (businessHours) and in settings
IsActiveInactive calendars cannot be selected by new consumers
IsDefaultThe org default; only one
TimeZoneSidKeyZone the day windows are expressed in
MondayStartTime … SundayEndTimeWindow per weekday; a day with no window is closed

Deployable metadata: one settings file

All calendars and holidays live in one file, settings/BusinessHours.settings-meta.xml, deployed as Settings with member BusinessHours (API 29.0+). Each businessHours entry carries name, active, default, timeZoneId, and the fourteen day-window fields in HH:mm:ss.SSSZ. Each holidays entry carries name, description, isRecurring, activityDate (non-recurring), recurrenceStartDate / recurrenceEndDate (recurring), and startTime / endTime, which are both null for a whole-day holiday. The full example is in references/examples.md; a second, single-region scenario with a genuine weekend-only calendar and full Metadata API field grounding is in references/metadata-examples.md.

Holidays are inert until attached

A holiday record does nothing by itself. It suspends time only for the calendars it is attached to, and a holiday can be attached to several calendars. "We added the holiday" with no attachment is the single most common reason a clock kept running on a public holiday.

Apex BusinessHours methods

All static, all take the calendar Id as a String; intervals are milliseconds.

MethodReturns
add(bhId, start, ms)Datetime reached after ms of business time from start, in the local time zone
addGmt(bhId, start, ms)Same, returned in GMT
diff(bhId, start, end)Business milliseconds between two datetimes
isWithin(bhId, target)true if target falls in business hours; holidays are included in the check
nextStartDate(bhId, target)Next datetime the calendar is open, or target itself if already open

Common Patterns

Pattern: Regional calendars selected at Case creation

When to use: Support teams in more than one region, one SLA policy, weekends and public holidays differ per region.

How it works:

  1. Create one calendar per region (time zone, windows) and attach that region's holidays to it.
  2. Keep the org default as the fallback region, not 24/7.
  3. Add a before-save record-triggered Flow on Case that sets BusinessHoursId from the account's region, the Case origin, or the entitlement. The Flow runs before the assignment rule and before any escalation timer starts.
  4. Point escalation entries at businessHoursSource = Case and milestones at the process default, so every consumer follows the Case's own calendar.

Why not one calendar: one calendar means every region's SLA pauses on one region's weekend and holidays.

Pattern: Working-time age in Apex or a formula-backed field

When to use: Reports need "business hours open" or a trigger needs to act after N working hours.

How it works: BusinessHours.diff(c.BusinessHoursId, c.CreatedDate, Datetime.now()) returns milliseconds of business time; divide by 3,600,000 for hours. Fall back to the default calendar when BusinessHoursId is null: [SELECT Id FROM BusinessHours WHERE IsDefault = true]. Formula fields cannot call the class, so write the result to a number field from a scheduled Flow or Apex.


Decision Guidance

SituationRecommended ApproachReason
Single support team, one time zoneEdit the default calendar; attach holidays to itEvery consumer already reads the default
Several regions with different holidaysOne calendar per region; set Case.BusinessHoursId at creationEscalation and milestones can follow the Case's calendar
One escalation entry must ignore hours (Sev-1)businessHoursSource = None on that entryEntry-level choice beats a per-Case calendar
SLA defined by contract tier, not regionCalendar at entitlement-process or milestone levelMilestones read the process calendar, not the Case field
Need "hours open" on a reportApex diff written to a fieldNo formula access to business time

  1. Inventory consumers — list every escalation entry (businessHoursSource), entitlement process, milestone override, and Apex call that reads a calendar; the agent /configure-business-hours does this as a referenced-by inventory
  2. Design calendars — one per distinct time zone plus holiday set; decide which is the org default and whether the shipped 24/7 default is acceptable
  3. Attach holidays — every holiday to every calendar it applies to; check the coming twelve months
  4. Set the Case calendar — a before-save Flow populates BusinessHoursId; document the rule and the fallback
  5. Deploy — retrieve Settings:BusinessHours first, edit, deploy the whole file; run scripts/check_business_hours_and_holidays.py on it
  6. Test with a clock — create a Case just before closing time and confirm the escalation or milestone target date lands on the next open window (references/examples.md)

Review Checklist


Salesforce-Specific Gotchas

  1. The default calendar is 24/7 out of the box — an org that never edited it runs every SLA round the clock while believing it "has business hours".
  2. Unattached holidays do nothing — a holiday suspends time only for calendars it is attached to; the record's existence alone changes nothing.
  3. Escalation entries pick their own source — an entry set to Static with a named calendar ignores the Case's calendar, and one set to None ignores all calendars; a regional design that only sets Case.BusinessHoursId is defeated by entries left on None.

Deeper treatment in references/gotchas.md.


Output Artifacts

ArtifactDescription
settings/BusinessHours.settings-meta.xmlAll calendars and holidays, deployable as Settings:BusinessHours
Case calendar ruleBefore-save Flow logic that sets BusinessHoursId, with fallback
Consumer mapEscalation entries, milestones, Apex callers and the calendar each reads
Clock test recordEvidence that an after-hours Case escalated in the next open window

Reference Files

FileRead it when
references/metadata-examples.mdWriting the deployable XML for a single-region scenario with a genuine weekend-only calendar and a named 24/7 severity tier — field-by-field Metadata API grounding with line citations
references/examples.mdTwo regional calendars end to end, the Case-calendar Flow, the Apex working-time helper, and the clock test
references/gotchas.mdBefore deploying, and whenever an SLA clock keeps running when it should have paused
references/llm-anti-patterns.mdReviewing AI-generated business-hours guidance or metadata
references/well-architected.mdChoosing one calendar vs one per region, and citing the sources behind any claim in this skill

Package files