http://www.developer.com/ws/proto/article.php/1567581/Building-WML-Gadgets-World-Time-Clock.htm
As mentioned in the last few articles, it is possible to add value to a mobile device by creating a small but ultimately useful application. In designing such an application, remember that the user will need to be online to use it, so the application's utility needs to be weighed against the potential cost of use. Note: Most mobile service plans offer a base amount of online time dedicated to "Web" use. So the user generally isn't paying more for the occasional gadget use. This article describes how to create another useful small application: a world time clock. This clock tells the time in prominent time zones and areas around the world. If you need to make a call to Sydney, Australia, for example, it would be nice to know if you are in danger of waking someone up, or are calling during the lunch hour. Our world time clock should accomplish the following: We could utilize only mobile technologies (WML and WMLScript) to accomplish our goals. However, we'd have to do the following: At first, this approach doesn't seem too bad. There are a finite number of time zones worldwide. However, you also have to take daylight saving time into account. For example, central Indiana (which includes Indianapolis) does not observe daylight savings. This means that Indiana, geographically in the Central time zone, seemingly bounces between Central and Eastern time zones. (In reality, central Indiana stays on Eastern Standard Time, and the zones around it shift.) A comprehensive open source database exists that can be used for this purpose. The database, often referred to as the tz or zoneinfo database, is packaged with most implementation of the GNU C Library, primarily Linux installations. Several tools are available for reading the data from the database, including a Perl module, Time::Timezone (available from CPAN, www.cpan.org). Note: As with previous articles, teaching Perl is out of the scope of this series. There are numerous sources on the Internet for learning Perl, including the tutorial at http://wdvl.internet.com/Authoring/Languages/Perl/PerlfortheWeb/toc.html. To start the script, we will simply output the time zones and the current time for each. The simple script shown below accomplishes this objective: #!/usr/bin/perl use Time::ZoneInfo ':all'; my $zones = Time::ZoneInfo->new(); foreach my $zone ($zones->zones) { This script simply creates a list of all the available zones and outputs each to the console. Next, we need to know what time it is in each zone. Fortunately, the operating system (Linux, in this case) can do the work for us. Most Linux applications that need to tell time do so by referencing the environment variable TZ. This variable contains the current time zone for the system. The OS can use this variable to decode its internal time clock into the correct value for the zone. If you change this variable and request the time from an application that uses it, you can easily tell the time in another zone. With help from the Date::Calc module, we can add the current time zone to our test: #!/usr/bin/perl use Time::ZoneInfo ':all'; my $zones = Time::ZoneInfo->new(); foreach my $zone ($zones->zones) { . . . Note that we simply change the TZ environment variable and call the System_Clock method. The variable is only changed within the application space, so the change in time zone doesn't affect the whole system--just our application. Next, we need the ability to search for a particular time zone. Adding a variable, "findzone", and a simple substring search accomplishes this goal: #!/usr/bin/perl use Time::ZoneInfo ':all'; my $findzone = (shift @ARGV); my $zones = Time::ZoneInfo->new(); foreach my $zone ($zones->zones) { $ENV{TZ} = $zone; print $year."-".$month."-".$day." "; Note the use of the IF statement. We uppercase both the zone and the findzone variables to help ensure a match (if "asia" is entered, it will still match all "Asia" entries). For example, running the script with this entry: ./tztest.pl pacific displays the following: Pacific/Easter: 2002-12-29 23:40:20 Suppose that the user doesn't know what time zone he/she is looking for. For example, Pacific/Honolulu covers Hawaii, but isn't necessarily intuitive to someone looking for "Hawaii." To help the user, we will add "ALL" as a valid search that returns all zones. To do so, we
doctor the IF statement accordingly: if (((index uc($zone), uc($findzone)) != -1) || Now, if the user enters "ALL" for the search, he/she will get all known zones. Using methods described in previous articles, it's relatively easy to output compliant WML for mobile devices. We will need another Perl module, CGI, for a couple of purposes: Note: After my calendar gadget article was posted, a reader wrote to chastise me for writing my own argument-parsing routine. As I stated in the article, the fact that the script was passing itself cleanly formatted parameters was justification for simple argument parsing. However, one point I missed (brought up by the reader) was that the code might go on to be incorporated in other scripts where the sterility of the parameters could not be guaranteed. To help promote solid coding, I've pledged to use the CGI method "param" from now on. To output a WML card, we use the following code: # Pass WML header This sets up the beginnings of a generic card. Subsequent PRINT statements can supply <do> and/or <p> tags accordingly. Let's close up the card: # Print closing tags Now all that's left is more Perl logic to control the flow and the resulting output. Here's a listing of our final script: #!/usr/bin/perl The most notable addition is the IF statement to control which card is displayed. When the script is first executed (without a parameter), the input card is displayed to allow the user to input search text. The script is then called again with the name/value pair "findzone" and the zones are searched for a match. We've also added logic to tell whether any results were returned. If no results were displayed, the code tells the user ("No time zone match for. . . "). Note: Pay particular attention to the escaped dollar sign ($) in the <go> tag. Without the escape backslash (\), Perl would interpret "$findzone" as one of its local variables. Since the Perl variable "$findzone" is empty when the script is first called, the resulting <go> tag would incorrectly be sent to the browser as follows: <go href="timezone.pl?findzone="/> As with previous projects, several things could be added to improve our world time clock: I'm interested in hearing what you need/want to do with WML.
I'll use some of the more challenging or common ideas in upcoming articles.
Send your ideas to the address below. Steve Schafer is the chief operating officer of Progeny
Linux Systems, a Linux-based consulting company in Indianapolis, Indiana. He
has written several technical books and articles and can be reached at sschafer@synergy-tech.com. This series of articles describes how to provide Web content to mobile devices through WML (Wireless Markup Language). This article covers creating small programs that extend the functionality of mobile devices, building on the previous two articles and examples. Note: These articles cover WML and WMLScript version 1.1, which are supported by the majority of mobile devices in use today. The articles assume a working knowledge of HTML and general Web technologies, and further assume that you have read the previous article(s) in this series. # # #
Building WML Gadgets: World Time Clock
January 10, 2003
Review
World Time Application
More Help from CGI
Starting the Script -- Reading Time Zones and Telling Time
Listing: tztest.pl
print $zone."\n";
}Listing: tztest.pl
use Date::Calc ':all';
$ENV{TZ} = $zone;
($year,$month,$day,$hour,$min,$sec, $doy,$dow,$dst) =
System_Clock();
print $zone.":";
print $year."-".$month."-".$day." ";
print $hour.":".$min.":".$sec."\n";
}Sample tztest.pl output:
America/New_York: 2002-12-29 23:35:22
America/Detroit: 2002-12-29 23:35:22
America/Louisville: 2002-12-29 23:35:22
America/Kentucky/Monticello: 2002-12-29 23:35:22
America/Indianapolis: 2002-12-29 23:35:22
America/Indiana/Marengo: 2002-12-29 23:35:22
America/Indiana/Knox: 2002-12-29 23:35:22
America/Indiana/Vevay: 2002-12-29 23:35:22
America/Chicago: 2002-12-29 22:35:22
America/Menominee: 2002-12-29 22:35:22
America/North_Dakota/Center: 2002-12-29 22:35:22
America/Denver: 2002-12-29 21:35:22
America/Boise: 2002-12-29 21:35:22
America/Shiprock: 2002-12-29 21:35:22
America/Phoenix: 2002-12-29 21:35:22
America/Los_Angeles: 2002-12-29 20:35:22
America/Anchorage: 2002-12-29 19:35:22
America/Juneau: 2002-12-29 19:35:22
America/Yakutat: 2002-12-29 19:35:22
America/Nome: 2002-12-29 19:35:22
America/Adak: 2002-12-29 18:35:22
. . .
Searching for Time Zones
Listing: tztest.pl
use Date::Calc ':all';
if ((index uc($zone), uc($findzone)) != -1) {
($year,$month,$day,$hour,$min,$sec, $doy,$dow,$dst) =
System_Clock();
print $zone.":";
print $hour.":".$min.":".$sec."\n";
}
}
Pacific/Galapagos: 2002-12-29 22:40:20
Pacific/Yap: 2002-12-30 14:40:20
Pacific/Truk: 2002-12-30 14:40:20
Pacific/Ponape: 2002-12-30 15:40:20
Pacific/Kosrae: 2002-12-30 15:40:20
Pacific/Tarawa: 2002-12-30 16:40:20
Pacific/Enderbury: 2002-12-30 17:40:20
Pacific/Kiritimati: 2002-12-30 18:40:20
Pacific/Majuro: 2002-12-30 16:40:20
Pacific/Kwajalein: 2002-12-30 16:40:20
Pacific/Auckland: 2002-12-30 17:40:20
Pacific/Chatham: 2002-12-30 18:25:20
Pacific/Tahiti: 2002-12-29 18:40:20
Pacific/Marquesas: 2002-12-29 19:10:20
Pacific/Gambier: 2002-12-29 19:40:20
Pacific/Johnston: 2002-12-29 18:40:20
Pacific/Midway: 2002-12-29 17:40:20
Pacific/Wake: 2002-12-30 16:40:20
Pacific/Honolulu: 2002-12-29 18:40:20
("uc($findzone)" eq "ALL" )) {Creating WML Cards
print header(-type=>'text/vnd.wap.wml');
# Print WML header and beginning tags
print <<ENDHEADER;
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML
1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card>
ENDHEADER
print <<ENDFOOTER;
</p>
</card>
</wml>
ENDFOOTERThe Final Script
Listing: timezone.pl
use Time::ZoneInfo ':all';
use Date::Calc ':all';
use CGI qw(:standard);
my $findzone = param('findzone');
# Pass WML header
print header(-type=>'text/vnd.wap.wml');
# Print WML header and beginning tags
print <<ENDHEADER;
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML
1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card>
ENDHEADER
# Do we have a time zone to look up?
if ( "$findzone" eq "" ) {
# No time zone specified; display input card
print <<INPUTCARD
<do type="accept">
<go
href="timezone.pl?findzone=\$findzone"/>
</do>
<p>
Enter zone text to search<br/>
for or ALL for all zones:
<input name="findzone" maxlength="40"
format="*A"/>
INPUTCARD
} else {
$findzone =~ tr/ /_/;
$findzone =~ tr/+/_/;
# Set up zones
my $zones = Time::ZoneInfo->new();
my $matches = 0;
print "<p>\n";
# Run through zones, looking for match
foreach my $zone ($zones->zones) {
if (((index
uc($zone), uc($findzone)) != -1) ||
(
"uc($findzone)" eq "ALL" )) {
# Display each
match, or all if "ALL" was entered
print
$zone." :<br/>";
$ENV{TZ} = $zone;
($year,$month,$day, $hour,$min,$sec,
$doy,$dow,$dst)
= System_Clock();
print
$year."-".$month."-".$day." ";
print
$hour.":".$min.":".$sec."<br/>\n";
$matches++;
}
}
# If no time zone matches, tell user
if ( $matches eq 0 ) {
print "No
time zone match for:<br/> \n";
print $findzone."<br/><br/>";
}
}
# Print closing tags
print <<ENDFOOTER;
</p>
</card>
</wml>
ENDFOOTER
# End of scriptRoom for Improvement
What Do You Want from WML?
About the Author
About this Series