Howwise RSS
VoIP & Phone Systems8 min read

FreePBX Time Conditions for Business Hours and Holidays

Short answer

FreePBX time conditions business hours routing works in two parts: a Time Group defines when you are open, and a Time Condition sends matching calls to the receptionist and non-matching calls to voicemail or an IVR. Build groups first, then conditions, then point the inbound route at the condition.

Key takeaways
  • Create Time Groups first, then Time Conditions, then set the Inbound Route destination to the top Time Condition.
  • Put the holiday condition upstream of the business-hours condition, because the first condition to decide wins.
  • FreePBX evaluates time using the server's system timezone, not your browser or phone clock, so verify with date and timedatectl.
  • A stuck manual override (*27) is the most common reason calls ignore the schedule; reset it and check with database show TC.
  • Always click Apply Config, then test with a time group shifted a few minutes around now.

How do FreePBX time conditions for business hours work with time groups?

The two objects have separate jobs. A Time Group only describes when: time-of-day ranges, days of the week, days of the month and months. It makes no routing decision.

A Time Condition evaluates a group at the moment a call arrives. If the current time is inside the group it goes to the Matched destination, otherwise to the Non-matched destination. Because conditions only reference groups, one group can be reused by many conditions.

A time condition is also a destination. That is why it can sit behind an inbound route, behind another time condition, or inside an IVR option.

Worked example: FreePBX time conditions for business hours, holidays and an override

The goal: ring the receptionist Monday to Friday 08:00 to 17:00, send holidays to a holiday greeting, and send everything else to an after-hours IVR. The call flow looks like this:

ObjectNameSettings
Time GroupTG-Hours-MainMon to Fri, 08:00 to 17:00
Time GroupTG-HolidaysMonth Jan, day 1; Month Dec, day 25 (add one entry per date)
Time ConditionTC-HolidayGroup TG-Holidays; Matched: Holiday announcement/voicemail; Non-matched: TC-Hours
Time ConditionTC-HoursGroup TG-Hours-Main; Matched: Ring Group Reception; Non-matched: IVR After-Hours
  1. Go to Applications > Time Groups and create TG-Hours-Main with start 08:00, finish 17:00, Mon to Fri. Leave month and day-of-month on their default (all).
  2. Create TG-Holidays. Add one entry per holiday with both Month and Day of Month set (for example Dec and 25). Setting only one of the two matches the whole month or every month's day.
  3. Go to Applications > Time Conditions. Create TC-Hours first so it exists as a destination: Matched to your reception ring group, Non-matched to the after-hours IVR.
  4. Create TC-Holiday: group TG-Holidays, Matched to the holiday announcement or voicemail, Non-matched to TC-Hours.
  5. Edit the Inbound Route for your DID and set its destination to Time Conditions: TC-Holiday.
  6. Click Submit, then Apply Config. Nothing is live until the reload completes.
  7. Test the boundary. Place one call at 16:59 and another at 17:00 (or temporarily shift the group's finish time to a few minutes from now and test the minute before and the finish minute). Expected result: the 16:59 call reaches Ring Group Reception and the 17:00 call reaches IVR After-Hours. Confirm this on your own system with asterisk -rvvv, then restore the group.
Inbound Route (DID)
   |
   v
TC-Holiday --match--> Holiday announcement / voicemail
   |
   no match
   v
TC-Hours ----match--> Ring Group: Reception
   |
   no match
   v
IVR: After-Hours (1 = on-call, 2 = voicemail)
Tip: Asterisk time ranges treat the finish time as exclusive. With a 17:00 finish, the group matches up to 16:59:59, and 17:00 is the first non-matching minute, so a call at 17:00:30 goes to the Non-matched destination. Enter your real closing time (17:00) as the finish. Do not enter 16:59, because that would stop matching one minute early, at 16:59. Verify with the 16:59 and 17:00 test calls in the last step above.

How do I route holidays and closures in FreePBX?

There are two approaches. The first is the chained holiday condition above. It needs no external services, but someone must edit TG-Holidays each year for floating holidays such as Thanksgiving.

The second is a calendar-based time condition. In the Time Condition's Mode setting, choose a Calendar or Calendar Group instead of a Time Group. The Calendar module (Applications > Calendar) can read Google, CalDAV or iCal sources, so a manager can add a closure to a shared calendar and the PBX picks it up on its next sync.

Calendar mode matches while an event is active. A common pattern is a calendar holding only closures, used as the first condition: Matched goes to the closed greeting, Non-matched goes to TC-Hours. Check that the calendar sync is working before relying on it, because a failed sync fails silently into Non-matched.

How do I add a manual override and a BLF toggle?

For snow days or unexpected closures you need a way to flip routing without editing groups. In each Time Condition, the feature code option enables a toggle. The default feature code is *27 (Time Conditions Toggle). In newer versions you can give a condition a Feature Code Index, and dial *27 followed by that index to toggle that specific condition.

The BLF hint name is built from that same number: the prefix Custom:TC followed by the condition's Feature Code Index. A condition with index 1 uses the hint Custom:TC1 and the BLF key value *271. A condition with index 3 would use Custom:TC3 and *273. Do not copy the example blindly; run core show hints on your own PBX and use the TC entry it lists for your condition.

The override states are: normal (follow the schedule), temporary override matched (act as open), and temporary override non-matched (act as closed). Each toggle press moves to the next state, and the system announces the new state if the audio prompt is enabled.

The override is stored in AstDB, so it persists across calls and reloads until someone toggles it back. In the Time Condition edit page, the Change Override setting also offers Reset Override. Tell staff plainly: after a snow day, reset it.

Derivation (index = the Feature Code Index set on the Time Condition):
  Hint name  = Custom:TC + index   -> index 1 gives Custom:TC1
  BLF value  = *27 + index         -> index 1 gives *271

Phone BLF key (example for index 1):
  Type:  BLF
  Value: *271
  Label: Open/Closed

Asterisk hint behind it (generated by FreePBX):
  Custom:TC1

Check the real name on your PBX:
  asterisk -rx "core show hints" | grep -i TC
Warning: Anyone who can dial the feature code can close the office to callers. Restrict the toggle to the receptionist and manager phones where practical, and remind staff to confirm the state after toggling.

Why is my time condition routing to the wrong destination?

Almost every failure falls into a handful of causes. Work through them in this order, from cheapest to check to most obscure.

SymptomLikely causeFix
Calls go after-hours during the day, or open too earlyServer timezone differs from local time (UTC cloud image, wrong install choice)timedatectl set-timezone, then fwconsole restart
Always open or always closed regardless of timeOverride left toggledDial the feature code until normal, or set Reset Override and apply
Closes at 16:00 in winter onlyDaylight saving shift or timezone set by fixed offsetUse a named zone like America/Chicago, not UTC-6
Edits seem to do nothingApply Config not runClick Apply Config, or fwconsole reload
Holiday does not triggerGroup has Day but no Month, or the holiday condition is downstreamSet both fields; move TC-Holiday upstream
Always goes to Non-matchedEmpty or overlapping time group, or wrong days selectedOpen the group, confirm it has at least one valid entry
Matched call goes to one extension, not the teamMatched destination points at an extension rather than a ring groupPoint to a Ring Group or a queue, and a shared voicemail box for failover
Callers hit the IVR before the schedule appliesTime condition placed after the IVR in the flowMake the Inbound Route point to the condition, and the IVR to be a branch of it
Tip: Also check for NTP drift on VMs. A clock that is several minutes off shifts every boundary, which is easy to mistake for a configuration bug.

How do I verify the clock, the override state and the call path?

FreePBX uses the operating system timezone, via Asterisk and PHP, and ignores your browser timezone and phone display. Check all three layers, fix the OS, then reload.

For call-path testing, shift TG-Hours-Main so it ends a few minutes from now, Apply Config, and place a real call before and after the boundary. Remember the finish minute is the first non-matching minute. Revert the group afterward. Watch the console while the call runs and look for the timeconditions context.

# OS clock and zone
date
timedatectl
timedatectl set-timezone America/Chicago   # use your own tz name
timedatectl set-ntp true

# PHP zone (should not conflict with the OS)
php -i | grep -i 'date.timezone'

# Apply and restart so Asterisk picks up the new zone
fwconsole reload
fwconsole restart

# Watch a live call
asterisk -rvvv

# Inspect generated dialplan and override state
asterisk -rx "dialplan show timeconditions"
asterisk -rx "database show TC"
asterisk -rx "core show hints" | grep -i TC
Warning: fwconsole restart drops active calls. Run it outside business hours or when the system is idle.

What should after-hours callers hear, and how do I keep this maintainable?

Choose the non-matched destination for the real need. A shared or general voicemail box is the simplest option and avoids a single person's mailbox going unheard. An after-hours IVR works well when it offers an emergency option, for example press 1 to ring an on-call ring group that includes an external mobile number via follow-me. An announcement followed by hangup suits businesses that do not take messages.

Record a clear greeting that states hours and the next step, and re-record it when hours change. Silence or a default greeting is the most common complaint callers have.

For several DIDs or sites, use one time condition per DID when hours differ, and share a time group between conditions when they do not. Use a naming convention that shows type, site and purpose, such as TG-NYC-Hours, TG-All-Holidays, TC-NYC-Hours. Because a group is edited in one place, a holiday added to TG-All-Holidays covers every condition that references it.

Common questions

Can one time condition cover lunch breaks?

Yes. Add two time ranges to the same group, for example 08:00 to 12:00 and 13:00 to 17:00 on Mon to Fri. Calls between the ranges go to the Non-matched destination, so point that at something suitable for a lunch break rather than the after-hours IVR.

Do time conditions apply to outbound calls or only inbound routes?

A time condition is a destination, so it applies wherever you point something at it: inbound routes, IVR options, ring group fallbacks and other conditions. It does not restrict outbound dialing by itself, which is controlled by outbound routes and their own settings.

Why does the override work from one phone but the BLF light does not change?

The BLF key must subscribe to the exact hint for that condition, and the phone must be able to subscribe to hints on the PBX. Run core show hints and confirm the TC entry exists, then check the key value matches the feature code with the index. Some phones also need the PBX address configured as the BLF subscription server.

Does a holiday on a weekend need its own entry?

Yes. The group matches the calendar date, so a Dec 25 entry fires whether it lands on a Saturday or a Monday. If you observe a holiday on a different day, such as the following Monday, add that observed date as its own entry.

How do I see which branch a call took?

Run asterisk -rvvv during a test call and read the Goto lines in the timeconditions context, which show whether the match or non-match branch executed. After the call, the CDR in Reports > CDR Reports shows the final destination reached.

Related topics:freepbxtime conditionsbusiness hoursasteriskcall routing