Apps :: Looking for World Time Application



Here's a better rendition, makes config file ~/.citytimerc, updates betweeen downloads using the system clock, etc

Width is now the total width.

Code Sample
#!/usr/bin/perl

# citytime - outputs times in multiple cities
# by wdef

# - downloads times from web at preset interval
# - caches and updates times using system clock between downloads

my $version = 0.3;

# Use -h for useage
# 24-hour, multi arg version
# -f option for long city listing
# -w option to set output width

# Note that die messages won't show in torsmo.

use strict;
use warnings;
use Getopt::Std;



#===================================// SUBS //=========================================

my ($download_interval, $defaultwidth, $download, $timecache, $timestamp, $city, $citytimerc, $timeurl1, $timeurl2, $URL, $displaywidth, %cachedtimes, $storedcity,  $storedtime, $storedmins);
our ($opt_f, $opt_h, $opt_w, $opt_v);


sub make_config_file {

my $conf;

$conf = <<HERE_TARGET

# Citytime will use these settings

# Download time from these URLs:
\$timeurl1 = "http://www.whattimeisit.com/cgitime.exe?Mode=FullList";

# -f option will enable:
# \$timeurl2 = someotherURL

# Minutes between downloads:
\$download_interval = 15;

# Default total output width in chars, overidden by -w switch
\$defaultwidth = 20;

# Cache file name & location
\$timecache = "/tmp/citytime.timecache";

# Time stamp file name & location
\$timestamp = "/tmp/citytime.timestamp";

# Downloaded time temp file name & location
\$download = "/tmp/citytime.html";

HERE_TARGET
;

open (CONFIG, "> $citytimerc");
print CONFIG "$conf";

}


sub add_leading_zero{
my $n = shift;
if (length($n) eq 1){ $n = '0' . $n }
return $n
}


sub twelveto24{
# adapted from http://keithdevens.com/weblog/archive/2006/Feb/02/12-to-24
   my ($hr, $per) = @_;
   return '00' if($hr == 12 and $per eq 'AM');
   return $hr+12 if($hr != 12 and $per eq 'PM');
   $hr = add_leading_zero($hr);
   return $hr;
}

sub check_cityargs{
# Check if city args have changed since the last call
my $arg;
open(CACHE, "<$timecache") or return 0;
foreach $arg(@ARGV) {
if ($arg !~ /\w+/) { die "City '$city' not alphanumeric" }
if (<CACHE> !~ /$arg/i){ return 0 }
}
# Check if DST status has changed
my @timecmps = localtime;
my $dst = $timecmps[8];
if (<CACHE> !~  /$dst/){ return 0 };
return 1;
}


sub maketimestamp {
open(TIMESTAMP, ">$timestamp") or die "Could not open $timestamp";
my $epochsec = time;
print TIMESTAMP $epochsec, "\n";
}

sub readcache {
open(CACHE, "<$timecache") or return 0;
my $diff = shift;
while (<CACHE>){
chomp;
$storedcity = "";
$storedmins = "";
# to handle spaces in city names.
if (/^(.+)\s(\d+)$/) {
$storedcity = $1; $storedmins  = $2
} else { last }

my $updated_citysecs = $storedmins * 60 + $diff;
my @parts = gmtime($updated_citysecs);
my $minutes = add_leading_zero($parts[1]);
my $hours = add_leading_zero($parts[2]);
my $updatedtime = $hours . ':' . $minutes;

my $F = 'A' . $displaywidth;
print pack("$F A5", $storedcity, $updatedtime), "\n";
}
return 1;
}

sub record_daylight_saving{
# Write local DST status to cache
# Probably only useful in EU for looking at other EU timezones
my @timecomps = localtime;
print CACHE $timecomps[8];
}


sub check_online {
open (NET, "ifconfig -a |");
while (<NET>){
if (/.+inet addr:(\d+\.\d+\.\d+\.\d+).+/){
if ( $1 ne "127.0.0.1" ) { return 1 }
}
}
return 0;
}

sub getfreshtime {
unless (check_online) { print "> No network <\n"; return 0 }
if ( -e $timecache ) { unlink $timecache } # start clean just in case
open(CACHE, ">$timecache") or die "Could not open $timecache";
system("wget -O $download $URL &>/dev/null");
open(CONT, $download) or return 0;
while (<CONT>){
foreach $city(@ARGV) {
if (/$city.+?(\d{1,2})\:(\d+\d+) ((AM|PM))/i) {
my ($hr, $min, $ampm) = ( $1, $2, $3);
my $newhr = twelveto24($hr, $ampm);
my $newtime = $newhr . ":" . $min;
my $totalmins = $newhr * 60 + $min;
maketimestamp;
print CACHE $city, " ", $totalmins, "\n";
my $F = 'A' . $displaywidth;
print pack("$F A5", $city, $newtime), "\n";
}
}
}
unlink $download;
record_daylight_saving;
return 1;
}

sub time_elapsed {
if (!open(TIMESTAMP, "<$timestamp") ){
if (getfreshtime) { exit(0)
} else { die "No webtime\n" }
}
my $timestamped_time = <TIMESTAMP>;
chomp $timestamped_time;
my $epochsec = time;
my $timediff = $epochsec - $timestamped_time;
return $timediff;
}


# ============================//SETTINGS//=====================================

$citytimerc = ${ENV}{'HOME'} . '/' . '.citytimerc';

if (! -r "$citytimerc") { make_config_file() }

# Use config file
eval `cat $citytimerc`;

# Parse  cli switches
getopts('fhvw:');

if ($opt_h) { die "Usage: $0 [-fhvw WIDTH ] somecity1 somecity2 somecity3 ..\n" };
if ($opt_v) { die "$version\n" };
if (!$ARGV[0]) {die "No city specified"};
if ($opt_w){
if ($opt_w !~ /\d+/ ) { die "Invalid argument to -w option"
} else { $displaywidth = $opt_w - 5 }
} else { $displaywidth = $defaultwidth - 5 }

if ($opt_f) { $URL = "$timeurl2"
} else { $URL = "$timeurl1" }


#==========================//MAIN//=============================================

print "www.whatisthetime.com:\n"; # acknowledge source

# if the timestamp can't be read then download, cache and display fresh time and exit.

my $difference = time_elapsed;

sub get_time {
getfreshtime || readcache($difference) || die "No time!\n";
}

# If argument cities have been added or the timecache  can't be read
# or if DST status locally has changed
# then download, cache and display fresh time and exit.

if (!check_cityargs) { get_time; exit(0) };


my $threshold = $download_interval * 60;  # threshold in seconds

# If the download interval has been exceeded, then download, cache and display fresh time and exit.
# Otherwise read the timecache and update to current time by adding on secs since the timestamp.

if ($difference >= $threshold ) { get_time; exit(0)
} elsif (!readcache($difference)) { getfreshtime || die "No webtime\n" }

# If network goes down when citytime needs to get fresh time, then >no network< will be displayed.

# If network goes down and interval is not up and cached stuff is ok, and cityfime refreshes from
# the web for another reason (eg changed args), then <no network< will be displayed AND display
# times will be updated using the system clock.


unlink $download;


Looks good so far.

I changed the .torsmorc line to read "execi 60" so that the times read the same as the system clock. Torsmo takes 100s to appear on my (slow) machine versus almost immediately without the .citytime call - it was probably as slow with the previous incarnations of .citytime.

It has to download the times page the first time it is run after bootup, that's going to slow things down.  I start my network connection after starting the desktop, so don't notice this.  Is this what the holdup is?

If you quit X and restart, it won't download again until the $download_interval period is up or something's happened to the cache or temp files etc. (Doing this on my 1.87Ghz machine, torsmo starts after about 3 sec, and I'm running several other scripts, hacks etc as well from it).

So that'll tell us if it's the download or something else holding up torsmo for you.

The torsmo config file does say that running external stuff from torsmo in this way consumes a lot of resources.

How's the blinking?  For me it's much improved, and seems to be coming from the other extra stuff I'm having torsmo do anyway.

I also use execi 60 - makes sense to refresh the minutes display every minute.

If I exit and then (re)startx, the torsmo display takes about 20s to appear and the world time digital clocks about 20s after that - this is on a 267MHz Pentium II...

I would say the blinking is about the same with/without .citytime

I could add an option to disable arg and local dst status checking, that would make no difference on my 1.87Ghz machine but might on yours.  If you say the previous citytime was just as slow, this isn't the problem anyway.

It seems to be taking a long time just to parse the cache file and update the times display on your machine, which is almost instantaneous on my machine.

If I knew more perl, I could probably make it run much faster.  It's not helped by calling system progs like wget as child processes -  a workaround because dsl lacks the standard LWN::Simple module (contains perl's 'get').

A lua version probably would go faster, but might still need to drop to perl/sed/awk in order to extract the times from the html.

In case anyone wants to write a version in another language, perl can be called from the shell to extract a time from the downloaded html file thusly:

Code Sample

export city=Boston
cat Zones.html | perl -ne 'my $city=${ENV}{city}; if (/$city.+?(\d{1,2})\:(\d+\d+) ((AM|PM))/i) {print $city, " ", $1,":",$2}'


But it could be that running external interpreters from torsmo like this is just not so wonderful in any case on low spec machines.

Next Page...
original here.