本文へ移動
cccskills
無料GitHub で公開

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. Covers the BusinessHoursSettings metadata, the default calendar, per-region calendars, holiday attachment, the Case Business Hours field, and the BusinessHours Apex class. Trigger keywords: business hours, holidays, SLA clock, escalation not pausing, working hours, support hours, milestone timer weekend. NOT for the escalation rule entries themselves — use admin/escalation-rules. NOT for entitlement process design — use admin/entitlements-and-milestones. NOT for Field Service operating hours or shift scheduling — use admin/fsl-scheduling-setup.

インストール方法を見る

含まれるファイル(8)

  • SKILL.md13.7 KB
  • references/examples.md9.7 KB
  • references/gotchas.md8.6 KB
  • references/llm-anti-patterns.md4.2 KB
  • references/metadata-examples.md12.9 KB
  • references/well-architected.md3.9 KB
  • scripts/check_business_hours_and_holidays.py10.2 KB
  • templates/business-hours-and-holidays-template.md2.1 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

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

  • Which calendar is the org default? Setup ships with a default calendar that is 24 hours, 7 days. Every consumer that is not told otherwise reads it, so an org that "has business hours" but never edited the default is still running SLAs round the clock.
  • Who reads the calendar? Escalation rule entries choose None, the Case's calendar, or a named calendar. Entitlement processes read the process-level calendar or a milestone-level override. Apex reads whichever Id you pass. Omni-Channel and approval processes read no calendar at all.
  • How does a Case get its calendar? Case.BusinessHoursId is empty unless something sets it. Empty means the default calendar for every consumer that says "use the Case's hours".
  • Time zone per calendar. Each calendar carries its own time zone; the daily windows are stored in that zone.

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

Recommended Workflow

  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

  • The org default calendar is intentional, not the shipped 24/7 default
  • Every calendar has the correct time zone and a window for each working day
  • Every holiday is attached to at least one calendar and the next twelve months are covered
  • Case.BusinessHoursId is populated at creation or the fallback is documented
  • Each escalation entry's businessHoursSource (None / Case / Static) is the intended one
  • Entitlement process and milestone calendars are reviewed with the process owner
  • Apex callers handle a null BusinessHoursId
  • A test Case created after hours produced a target time in the next open window

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

Related Skills

  • admin/escalation-rules — the entries that consume the calendar through businessHoursSource
  • admin/entitlements-and-milestones — process-level and milestone-level calendars
  • admin/case-management-setup — where Case.BusinessHoursId is set in the intake design
  • admin/assignment-rules — routing runs at save; the calendar only governs what happens afterwards
  • admin/omni-channel-routing-setup — a negative check: Omni-Channel availability has no calendar input
  • flow/record-triggered-flow-patterns — the before-save Flow that populates the Case calendar

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Use this skill when writing test-first, behavior-driven acceptance criteria in Given/When/Then format for a Salesforce user story. Covers happy path, edge cases, negative paths, permission boundaries, and data-state preconditions so the AC block can drive UAT scripts and Apex test design downstream. Trigger keywords: given when then, gherkin, behavior driven AC, test first acceptance criteria, scenario outline, BDD acceptance criteria. NOT for the user-story format itself (use admin/user-story-writing-for-salesforce). NOT for UAT script writing (use admin/uat-test-case-design). NOT for Apex test method generation (use agents/test-class-generator). NOT for high-level UAT planning (use admin/uat-and-acceptance-criteria). More triggers: acceptance criteria record, ac_id, req_id on a criterion, artefact under test, negative case for a rule-type requirement, no-match fall-through criterion, oracle for a Then clause, test type apex flow manual, criteria linter, check_ac_format.py, --manifest-dir.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Task and Event objects: polymorphic WhatId/WhoId, Activity object model, ActivityHistory vs OpenActivity, activity timeline customization, bulk task creation, Einstein Activity Capture boundaries. NOT for turning on EAC or calendar sync — use admin/einstein-activity-capture-setup. NOT for Email-to-Case — use admin/case-management-setup. Covers ActivitiesSettings metadata, enableActivities, shared Task/Event custom fields and FLS, TaskStatus value sets, Shared Activities and TaskRelation/EventRelation, recurring and child activities, and partial-success bulk DML on Task.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Design Invocable Apex actions that return deterministic, agent-friendly errors instead of surfacing raw exceptions to the LLM. NOT for authoring the action itself — @InvocableMethod schema, labels, security context — use agentforce/custom-agent-actions-apex. NOT for the Apex tests that force each error branch — use agentforce/agent-action-unit-tests.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Use when designing how an Agentforce agent extracts structured input parameters (slots) from a user's natural-language utterance to invoke an action. Triggers: 'agent extract date from user', 'agent action argument extraction', 'agentforce slot filling', 'agent invocable input mapping', 'agent fails to fill required parameter'. NOT for action authoring (use agentforce/agent-actions) or for prompt-template variable binding (use agentforce/prompt-builder-templates).

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Apex test patterns for @InvocableMethod agent actions: per-reason-code branch coverage, bulk safety, callout mocking, deterministic assertions. NOT for testing whether the agent routes to the right topic or answers well — use agentforce/agent-testing-and-evaluation. NOT for designing the error envelope the tests assert on — use agentforce/agent-action-error-handling.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Designing or reviewing Agentforce actions: Flow actions, Apex invocable actions, prompt-template actions, action naming, input and output contracts, confirmation requirements, and safe error behavior. Triggers: 'agent actions', 'build an agent that can look up an order', 'make the agent able to check order status', 'give the agent a capability', 'agent that can retrieve a record', 'flow action for agent', 'agent invocable action', 'action schema design'. NOT for writing the Apex class itself — use agentforce/custom-agent-actions-apex. NOT for the reason_code error envelope that stops an agent retry loop — use agentforce/agent-action-error-handling.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

PranavNagrecha のスキルをすべて見る

このスキルの問題を報告する