Skip to main content

Time of Day and Holiday Routing

About

Time of day routing allows calls to be sent to different extensions based upon the time of day, day of week and in some cases, holidays. As of SVN revision 14385, FreeSWITCH supports a number of matchable variables for time and date elements. These are discussed in the Dialplan XML wiki page. The new matching variables obviate the need for using the strftime API. (You may still use strftime if you so choose or if you have a specific need that only strftime meets.)

Click here to expand Table of Contents

Variables

AttributeAcceptable ValuesDescription
year0 - 9999calendar year
yday1 - 366day of year
mon1 - 12month (Jan = 1, etc.)
mday1 - 31day of month
week1 - 53week of year
mweek1 - 6week of month
wday1 - 7day of week, numeric (sun = 1, mon = 2, etc.)
sunmontuewedthufrisatday of week
hour0 - 23hour
minute0 - 59minute (of the hour)
minute-of-day1-1440minute of the day (midnight = 1, 1am = 60, noon = 720, etc)
time-of-dayhh:mm-hh:mmtime rangeExample: 08:00-17:00
hh:mm:ss-hh:mm:sstime range, with seconds
date-timeYYYY-MM-DD hh:mm~YYYY-MM-DD hh:mmdate time range, note the ~ delimiterExample: 2010-10-01 00:00:01~2010-10-15 23:59:59
YYYY-MM-DD hh:mm:ss~YYYY-MM-DD hh:mm:ssdate time range, with seconds, note the ~ delimiter

These can be combined in the same condition, e.g:

<condition wday="6" hour="8-12"> 

Wrap-Around

Time and date variables support wrap-around to span the changing of the days, months, or years:

<condition mon="10-2"> <!-- from October of year 1 to February of year 2 -->
<condition time-of-day="17:00:00-07:00:00"> <!-- from 5PM of day 1 to 7AM of day 2 -->

(warning) If you use wrap-around then the from and to date/time need to be one value lower so 5:00:00-5:00:00 will read as 0 and needs to be 5:00:00-4:59:59 which would then read as 5AM from today to 4:59AM tomorrow.

Blocks

Comma–separated values allow discrete blocks of time to be specified:

<condition time-of-day="08:00-12:00,13:00-17:00"> <!-- from 8AM to 12AM and 1PM to 5PM -->
<condition date-time="2015-03-01 00:00:00~2015-03-01 23:59:59,2015-06-05 00:00:00~2015-07-01 23:59:59"> <!-- day 2015-03-01 and range from 2015-06-05 to 2015-07-01 -->

(warning) the tilde ~ character is used to delimit the starting date time and the ending date time

Time Zone Manipulation

By default, time–based routing uses the local time kept by FreeSWITCH. If you want to use a different time zone, you have 2 options (as of 2012-11-01 in master, see FS-4741 -Authenticate to see issue details ).

timezone

string Sets the timezone for this particular call. Can be used, e.g., to set the timezone for a caller who is checking his/her voicemail. The value is expressed in Linux timezone format (ex. America/New_York -- see /usr/share/zoneinfo/zone.tab for the standard list of Linux timezones).

(warning) this variable must actually be set before the comparison, so either set it inline, transfer, or set it in the user directory.

See also: Time of Day and Holiday Routing.

Usage

You can set the time zone globally for Freeswitch in /conf/vars.xml

<X-PRE-PROCESS cmd="set" data="timezone=America/Toronto"/>

Specify the timezone in the dialplan:

<action application="set" data="timezone=Asia/Seoul"/>
<action application="set" data="timezone=GMT0"/>
<action application="set" data="timezone=America/New_York"/>

In the directory:

<param name="timezone" value="America/New_York"/>

tod_tz_offset

integer Sets the GMT offset to be used on this call for time of day conditions.

(warning) this variable must actually be set before the comparison, so either set it inline, transfer, or set it in the user directory.

Usage

To set the offset global in conf/vars.xml:

<X-PRE-PROCESS cmd="set" data="tod_tz_offset=5"/>
<action application="set" data="tod_tz_offset=5"/>

Usage

The examples presented here can be added to the conf/dialplan/default.xml file or you can create a new file in conf/dialplan/default/ to be included in the default dialplan (see the bottom of the vanilla default dialplan).

Provision an internal extension # for Sales to route calls dialed for 2002.

conf/dialplan

   <extension name="RS-Sales-x2002">
<condition field="destination_number" expression="^2002$">
<action application="transfer" data="RS-Sales"/>
</condition>
</extension>

Setup variables prior to transferring to call handler for sales. This sets the variables so that they will be available to the condition test during the next pass through the dialplan initiated by the transfer app.

conf/dialplan

   <extension name="RS-Sales" continue="true">
<condition field="destination_number" expression="^RS-Sales$"/>
<condition wday="2-6"/>
<condition minute-of-day="540-1020">
<action application="set" data="RS-Sales_open=true"/>
<action application="transfer" data="xfer-to-sales"/>

<anti-action application="set" data="RS-Sales_open=false"/>
<anti-action application="transfer" data="xfer-to-sales"/>
</condition>
</extension>

Handle Sales Call

If Sales is open then route to extension first, then vMail; else send call directly to vMail. In this example, Sales have their own mailbox (#2001) - the configuration of that box forwards all vMail to email and does not store a local copy.

conf/dialplan

   <extension name="xfer-to-sales">
<condition field="destination_number" expression="^xfer-to-sales$"/>
<condition field="${RS-Sales_open}" expression="^true$">
<action application="bridge" data="user/1001@${domain_name}"/>
<action application="answer"/>
<action application="sleep" data="2000"/>
<action application="voicemail" data="default ${domain_name} 2001"/>

<anti-action application="voicemail" data="default ${domain_name} 2001"/>
</condition>
</extension>

VoiceMail Config (in conf/directory/default/2001.xml)

Voicemail config

 <user id="2001" number-alias="2001">
<params>
<param name="password" value="2001"/>
<param name="vm-password" value="2001"/>
<param name="vm-email-all-messages" value="true"/>
<param name="vm-notify-email-all-messages" value="true"/>
<param name="vm-attach-file" value="true"/>
<param name="vm-mailto" value="sales@foo.com"/>
<param name="vm-notify-mailto" value="chris@foo.com"/>
<param name="vm-keep-local-after-email" value="false"/>
</params>
<variables>
<variable name="toll_allow" value="domestic,international,local"/>
<variable name="accountcode" value="2001"/>
<variable name="user_context" value="default"/>
<variable name="effective_caller_id_name" value="sales"/>
<variable name="effective_caller_id_number" value="2001"/>
<variable name="outbound_caller_id_name" value="$${outbound_caller_name}"/>
<variable name="outbound_caller_id_number" value="$${outbound_caller_id}"/>
<variable name="callgroup" value="fga"/>
</variables>
</user>

Examples

Office Hours

Example for office open 09:00-16:00

Has inbound DID routed to extension 5001. Because the office_status variable is set with the inline attribute, the variable takes effect immediately with no need to transfer to another extension definition. The following dialplan extension will always be executed and continue after matching.

Time and day evaluation

 <extension name="Time of day, day of week setup" continue="true">
<condition wday="2-6" minute-of-day="540-960" break="never">
<action application="set" data="office_status=open" inline="true"/>
<anti-action application="set" data="office_status=closed" inline="true"/>
</condition>
</extension>

This extension will be evaluated if 5001 is the destination number and will build a final destination consisting of 5001_open or 5001_closed.

Ext. 5001

 <extension name="tod route, x5001">
<condition field="destination_number" expression="^(5001)$">
<action application="execute_extension" data="5001_${office_status}"/>
</condition>
</extension>

Now the call is handled.

Open/closed call handler

 <extension name="office is open">
<condition field="destination_number" expression="^(5001_open)$">
<action application="set" data="domain_name=$${domain}"/>
<action application="answer"/>
<action application="playback" data="/usr/local/freeswitch/recordings/welcome_message.wav"/>
<action application="set" data="hangup_after_bridge=true"/>
<action application="set" data="continue_on_fail=NORMAL_TEMPORARY_FAILURE,USER_BUSY,NO_ANSWER,TIMEOUT,NO_ROUTE_DESTINATION"/>
<action application="set" data="ringback=local_stream://moh"/>
<action application="set" data="transfer_ringback=local_stream://moh"/>
<action application="pre_answer"/>
<action application="bridge" data="{ignore_early_media=true,origination_caller_id_number=XXXXXXXX}sofia/gateway/<gateway name>/XXXXXXXX,sofia/gateway/<gateway name>/XXXXXXXX"/>
</condition>
</extension>

<extension name="office is closed">
<condition field="destination_number" expression="^(5001_closed)$">
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="playback" data="/usr/local/freeswitch/recordings/9-16.wav"/>
<action application="sleep" data="500"/>
<action application="hangup" data="NORMAL_CLEARING"/>
</condition>
</extension>

Holiday Routing

Similar to time of day routing, holiday routing can be used to route calls when your office is closed due to various company or national holidays.

Often these holidays fall on consistent dates and you can use the mday and mon attributes to detect them. Here is Christmas for example:

Fixed date

 <!-- Christmas day -->
<condition mday="25" mon="12">

However, some holidays don't fall on consistent dates and are instead something like 'the third Monday in February'. You can use the mweek (week of month) condition parameter (added in r15723) to help with this:

Third Monday

 <!-- president's day is the 3rd Monday in February -->
<condition wday="2" mweek="3" mon="2">

Sometimes, again, a holiday is specified as something like the 'last Monday in October' and you have to do something like this:

 <condition wday="2" mon="10" mday="25-31">

This works because the last Monday in October is guaranteed to fall in the last 7 days of the month (the 25th to the 31st) and this condition doesn't pass unless everything evaluates to true.

Using these three patterns you can match almost any holiday date, however, there are complicated ones like Easter and Inauguration Day that are more complicated and would require some custom coding to detect.

Memorial Day

Memorial Day

 <extension name="2012_memorial_day_weekend_routing">
<condition date-time="2012-05-25 17:00:01~2012-05-29 08:00:00"/>
<condition field="destination_number" expression="^1(2135551212)$">
<action application="bridge" data="sofia/external/18185551212@1.2.3.4"/>
</condition>
</extension>

There are more examples in the default dialplan that cover all US federal holidays except for inauguration day.