Time-Zone Processing with Asterisk, Part I

 in
Use Asterisk to adjust for your daylight hours.
Step 2: Confirming the Time-Zone Information

As convenient as it would be to have a reliable database of IP addresses mapped into the right time zones, there is still the problem of handling summer shifts in time. Plus, the estimate comes from a demonstration database that is not guaranteed to be accurate. Therefore, the AGI script is called from within an extension that is used to confirm the estimate or save a new one. For the confirmation step, I created an extension with the number *89 (because 8–9 is the numerical mapping of the letters T–Z). Just as with the previous program, some of the debugging statements are removed for brevity, but the full version is available from the LJ FTP site (see Resources).

This article shows the dial plan information entry in the Asterisk Expression Language (AEL). I started using AEL because it has better control structures and it is much easier to write structured code. For voice menus, the superior control structures in AEL allow much easier validation of input.

A call into the extension begins with a welcome announcement and a call to the script (shown previously) to estimate the time zone. All of the time-zone confirmation greetings are stored in the msg/tz subdirectory of the Asterisk sound library. Asterisk's SIPCHANINFO can be used to get SIP channel information. Specifically, the value of SIPCHANINFO(recvip) is the routable Internet address that the remote device used to register and, therefore, will work even if the remote device is behind a network address translator:

_*89 => {
     Answer;
     Playback(msg/tz/tz-wizard-welcome);
     Set(PEERIP=${SIPCHANINFO(recvip)});

     // Geolocate as a first stab at time zone
     AGI(tz-lookup.pl,${PEERIP});
     NoOp(TZ offset from script is ${TZ_OFFSET});

The script returns a guess at the time zone of the IP address used by the SIP peer in the TZ_OFFSET variable. However, the whole purpose of this call is to confirm the offset, so we proceed to a series of confirmation steps. The system starts by giving a confirmation of the time offset from the time in London and uses that to say the time. Asterisk keeps internal time as epoch time (the number of seconds past midnight on January 1, 1970 GMT) and converts it to local time for a given time zone. I am handling any adjustments to the time for summer months with a sledgehammer, which assumes that most of the countries I visit will be on roughly the same schedule as the UK and corrects any errors later in the validation step:

playoffset:
   Playback(msg/tz/tz-you-are-at);
   SayDigits(${TZ_OFFSET});
   Playback(msg/tz/tz-hours-to-london);

playtime:
   // London time keeps summer time
   Playback(msg/tz/tz-current-time-is);
   SayUnixTime($[${EPOCH}+${TZ_OFFSET}*60*60],
        Europe/London,A \'digits/at\' IMp);

Next, we ask the user to confirm whether the time is correct. The Read() application gets one digit from the user. AEL's switch statement is very handy for working with user input, because it can be used to set up a series of actions for a voice menu quite easily without extensive use of a forest of branching statements.In this case, the switch statement offers the option of a one-hour correction by entering the number 1, an arbitrary correction with the number 2 and an error statement that jumps back to the start of the time readout if anything else is pressed. The only catch in using goto within a switch statement in AEL is that due to the internal representation of the control structures, you must use a fully qualified goto, including the context, extension number and label. My internal extension context is from-internal, so gotos are prefaced with from-internal|*89:

Read(INPUT,msg/tz/tz-confirm-correct,1);
switch (${INPUT}) {
     case 1:
          goto from-internal|*89|expiry;
     case 2:
          goto from-internal|*89|correction;
     default:
          Playback(msg/tz/tz-1-or-2-please);
          goto from-internal|*89|playoffset;
};

At the correction label, there is a second option. I expect that summer-time errors will be common in actual use, so I added an expedited one-hour correction that can add or subtract an hour easily. The menu that handles the type of correction and the one-hour correction subroutine is available on the LJ FTP site. In structure, both are similar to the switch statement shown previously.

When I arrive in faraway locations, I am usually quite tired, and my ability to do mental arithmetic is substantially reduced from my capacity when fully functional. Rather than a voice menu to select a location, the menu prompts for the local clock time and computes the time-zone offset from the time in London. The basic algorithm is to obtain the 24-hour reference time in London with Asterisk's STRFTIME function and compute the offset from the time entered by the user. There's a possibility that the resulting offset will be too big or too small, so the script corrects for that:

      
gmtskew:
   Read(INPUT,msg/tz/tz-24-hour-prompt,4);
   Set(REMOTEHR=${INPUT:0:$[${LEN(${INPUT})}-2]});
   Set(REFERENCEHR=${STRFTIME(${EPOCH},
        Europe/London,%H)});
   Set(TZ_OFFSET=$[${REMOTEHR}-${REFERENCEHR}]);
   // correct for too big/too small offsets
   if ( ${TZ_OFFSET} > 12 ) {
        Set(TZ_OFFSET=$[${TZ_OFFSET}-24] );
   };
   if ( ${TZ_OFFSET} < -12 ) {
        Set(TZ_OFFSET=$[${TZ_OFFSET}+24] );
   };
   Return;

When the user confirms the time offset, the changes are saved in the Asterisk database with the DB function. Part of saving the changes is to ask the user for how long the offset should be saved. This code prompts for the number of days, though that part of the code easily can be extended to ask for an expiration date and time. After determining the time when the offset expires, the offset is read back to the caller in both the time at the remote site, as well as the home location. (Note that my home location is US/Pacific; you will need to replace that with your own time zone.)

For record-keeping purposes, four variables are stored with the name of the extension that controls the offset. There is the actual offset, as well as a start time, expiration time and the IP address of the SIP peer. If the device is moved before the end of the offset, we want to re-confirm the time offset automatically:

expiry:
    Set(NOW=${EPOCH});
    Set(CURRENT_OFFSET_TIME=$[ ${EPOCH} +
         ${TZ_OFFSET}*60*60 ]);
    Set(DB(tz/${PEERNAME}-TIMESKEW)=${TZ_OFFSET});
    Set(DB(tz/${PEERNAME}-TIMESKEW_START)=${NOW});
    Set(DB(tz/${PEERNAME}-TIMESKEW_ADDR)=${PEERIP});

    Playback(msg/tz/tz-your-offset-of);
    SayDigits(${TZ_OFFSET});
    Playback(msg/tz/tz-hours-relative-to-london);
    Playback(msg/tz/tz-confirm-time);
    SayUnixTime(${CURRENT_OFFSET_TIME},
         Europe/London,A \'digits/at\' IMp);

expiration-confirm:
    Read(TZ_DURATION,msg/tz/tz-days-active,2);
expiration-readout:
    Set(DB(tz/${PEERNAME}-TIMESKEW_END)=
         $[${NOW}+24*60*60*${TZ_DURATION}]);
    Playback(msg/tz/tz-shift-active-for);
    SayDigits(${TZ_DURATION});
    Playback(msg/tz/tz-days);
    Read(INPUT,msg/tz/1-if-right--2-if-wrong,1);
    switch (${INPUT}) {
         case 1:
              // Everything is OK, read out results
              NoOp(Go to result read-out);
              break;
         case 2:
              goto *89|expiration-confirm;
         default:
              Playback(msg/tz/tz-1-or-2-please);
              goto *89|expiration-readout;
    };
______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

for accurate local time...

Anonymous's picture

I'd recommend interfacing to the World Time Engine API.

You can check the timezone info that you're likely to get on the main website @ http://worldtimeengine.com.

It works a treat for one of our IVR services we've got running.

excellent article

directory submission's picture

Calling people across time zones might prove to be inconveniencing to the receiving party, especially if it’s late at night or very early in the morning. This is an excellent article on how to make Asterisk redirect inbound callers to a message informing them that they are calling at inconvenient hours.

Very well written

SoftArea51's picture

I find this article to be very useful and I think more articles like this can help us go deeper into Asterisk.

i think so too

schnäpel's picture

my thoughts ... a little bit more informations and i will be an "asterix-magican" :-) ok i´m far away from that but i´m willing to learn and linuxjournal is allways a good resource.

i agree

Oman's picture

i agree with you schnäpel - linuxjournal is for me the ultimative ressource i only find here the stuff if searched for. excellent website i love it.

linüx

evden eve nakliyat's picture

I hope linüx come number one

Asterisk

rbytes reviews's picture

evden, i hope too :)
To Bruce Byfield: good article, thanks!

linux is good but ..

online gewinnen's picture

i hope not! there far to less software development to be number one.

Yes, Great article, I agree

softsea's picture

Yes, Great article, I agree with this feature of asterisk seem cool, but I don't think it is very necessary.

A simpler suggestion

Tanner Lovelace's picture

Very cool use of Asterisk, but I might suggest a much simpler way of dealing with the problem:

Turn your cell phone off when you don't want people to call you on it. I recently went to Spain and took my GSM cell phone with me, but when I wasn't using it, I turned it off. That way no random calls waking me up in the middle of the night! Sure, it's not as cool as setting up Asterisk to tell callers you're in a different timezone, but for most people it makes a lot more sense.

not while traveling

Anonymous's picture

I want my family to be able to contact me *anytime* while I'm not at home or work. I'll tolerate the occasional wrong number, or mis-calculated time zone difference, rather than cut myself off from my loved ones.

or 2 numbers

Lawrence D&#039;Oliveiro's picture

Another answer to that is to have 2 numbers, an unlisted one for family and other close people, and a listed one for everybody else. Have them both go through your Asterisk server, and through to your real phone. Disable accepting calls from the listed one when it's not convenient.

You are absolutely right !

Wiersze's picture

I agree with you that two numbers it's very good solutions, btw are there any cell phones with cover two sim cards at time?

Greg

Time-Zone Processing

Mike Walker's picture

Whether or not you agree with the method used to solve the original problem this solution does a great job of exploring what can be achieved by exploiting the AGI. Hopefully other readers will create equally alternative uses engaging the AGI. After all the purpose here is surely to expand the general awareness of what Asterisk can be made to do. Let's not knock someone down just because we don't agree with their reasoning for a given implementation.

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState