Time-Zone Processing with Asterisk, Part I

 in
Use Asterisk to adjust for your daylight hours.

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:

#!/usr/bin/perl -w
# Asterisk AGI to estimate time zone from IP address

use strict;
use Asterisk::AGI;
use Geo::IP::PurePerl;
use POSIX qw(ceil floor);

# California is GMT -8
my $HOME_OFFSET = -8;

my $AGI = new Asterisk::AGI;
my %input = $AGI->ReadParse();

(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:

my $addr = $ARGV[0];
my @octets = split(/\./,$addr);

if (($octets[0] eq "192") && ($octets[1] eq "168") &&
   ($octets[2] eq "1")) {
  # Local IP addresses get the home offset
  $AGI->set_variable("TZ_OFFSET",$HOME_OFFSET);
  exit 0;
}

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:

my $gi = Geo::IP::PurePerl-> new(
   "/usr/local/share/GeoIP/GeoLiteCity.dat",
   GEOIP_STANDARD);

my $cityref = $gi->get_city_record_as_hash($addr);

if (!(defined ($cityref->{"longitude"}))) {
  # Guess at the home time when longitude undefined
  $AGI->set_variable("TZ_OFFSET",-8);
  exit 1;
}

my $longitude=$cityref->{"longitude"};

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:

my $numerator;
my $denominator=15;

if ($longitude>0) {
   $numerator=$longitude+7.5;
   $quotient=floor($numerator/$denominator);
} else {
   $numerator=$longitude-7.5;
   $quotient=ceil($numerator/$denominator);
}

$AGI->set_variable("TZ_OFFSET",$quotient);
______________________

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