Time-Zone Processing with Asterisk, Part I

Last year, I took a trip to Asia. To stay in touch, I carried a GSM world phone, capable of receiving
telephone calls in the countries I was visiting. The capability to receive calls with the same mobile phone number
I use at home while halfway across the world seemed incredibly cool—at least until the first call came in!
Mobile phones hide the location of the phone, which cuts both ways. A colleague had decided to call me in the
middle of the day on a Friday, which had awakened me very early on Saturday morning, because the phone
“hid” my faraway location from him.

After returning home, I asked several people why my phone company could not simply play a message to warn
callers when my time zone changes by more than four or five hours, letting them know the call might be
inconvenient. Nobody could come up with a technical reason, but we all suspected it was because the mobile phone
company to which I subscribed charged several dollars per minute to connect calls. As part of the process of
attaching a GSM phone to a network, the home network needs to learn where the phone is visiting, and that
information conceivably could include a time zone.

I returned to my idea once I started using Asterisk, because it provides an extensive toolkit for designing
PBX-hosted services. Anything that can be coded in a computer can become an Asterisk service. After I understood
the basics of Asterisk, I sat down to implement a feature that kept track of the time of day where I visited and
prevented calls from coming in at inconvenient times.

The system I built on top of Asterisk to handle this feature has two major parts. The key to the system is
maintaining a time-zone offset from the time in London. (My code implements offsets only of whole hours, though it
could be extended to use either half or quarter hours.) When a device first connects to Asterisk, its IP address is
used to guess the location and, therefore, the time offset. After the offset is programmed into the system,
incoming calls are then checked against the time at the remote location. Before the phone is allowed to ring, the
time at the remote location is checked, and callers can be warned if they are trying to complete a call at an
inconvenient time.

Step 1: Estimating the Time Zone

Asterisk does not have a built-in method to estimate the time zone from an IP address, but it does have the
next best thing—the Asterisk Gateway Interface (AGI). AGI programming allows an Asterisk extension to pass
data to an external program, do computations in that program and return results as Asterisk channel
variables.

I began the project by writing an AGI script that would take an IP address as input and return an estimated
time zone. Several existing geolocation databases map IP addresses into geographic information. None of the free
products or compilations I tried for this project could return a time zone directly from the database, so I
estimated the time zone based on the longitude. (The earth's surface has 24 time zones, each of which is
approximately 15 degrees of longitude.) After trying several databases, I settled on MaxMind's GeoLite City, a
free-for-non-commercial-use version of the comprehensive GeoCity commercial database.

GeoCity has APIs available in several programming languages. I used Perl, because there is also an AGI
library module for Perl that makes handling AGI scripts easier. As input, the program takes an IP address, and then
it needs to return the time zone. I used the convention of returning the time zone as an offset of the number of
hours from the time in London, which leads to some differences in daylight time handling.

The start of the program pulls in utility functions, including the Asterisk::AGI module, which decodes all
the parameters passed to the program by Asterisk:

(The full listing of programs from this article is available on the
Linux Journal FTP site; see Resources.) The argument to the program is an IP address, which is
given to us by Asterisk. The first check is to determine whether the IP address is on the local subnet of the
Asterisk server, 192.168.1.0/24. Most location databases don't include RFC 1918 address space and won't return a
lookup. The MaxMind API can accept a domain name as an argument, but we don't expect to pass it one:

The use of the database is straightforward. We create a new object, telling the API the location of the
database on disk, and then call the get_city_record_as_hash function in MaxMind's API, which returns everything
about the IP address as a hash. The item of interest is the longitude component of the hash. If there isn't one,
we'll simply return -8 for California and let Asterisk deal with the problem:

A bit of math is required to deal with the fact that time-zone boundaries may be 15 degrees, but zero degrees
is in the middle of a time zone. We can use two formulas, depending on whether the longitude is positive or
negative. After computing the time zone, we pass it back to Asterisk in the TZ_OFFSET channel variable, where it is
available for use in the dial plan:

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 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.

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.

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.

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.