Ein Skript rechnet Währungen entsprechend den aktuellen Umtauschkursen einfach auf der Kommandozeile um.
Um hundert DM in Euro zu konvertieren, installiert man das
heute vorgestellte Skript ccon
, tippt
$ ccon 100 DEM EUR 51.1292
ein und erhält mit 51.1292
sofort das richtige Ergebnis. Und wieviel Dollars
bekommt man für 100 Euros?
$ ccon 100 EUR USD 92.06
92 Dollars und 6 Cents, richtig, denn zum Zeitpunkt der Entwicklung dieses Skripts war der Dollar gerade auf 1.086248 Euro. Hexerei? Keineswegs.
Yahoo und einige andere Anbieter stellen die aktuellen Umtauschkurse
kostenlos auf dem Internet zur Verfügung.
Das Modul Finance::Currency::Convert
von Jan Willamowius
abstrahiert diesen Zugriff schön, die objektorientierte Schnittstelle
offeriert einfach eine Methode convert()
, die den
Geldbetrag, die Ausgangs- und die Zielwährung erwartet und
das Ergebnis zurückliefert.
Eine Auswahl der verfügbaren Währungen und deren Kürzel:
EUR Euro DEM Deutsche Mark USD US-Dollars GBP Britische Pfund ATS Österreichische Schilling ESP Spanische Peseten FRF Französiche Franc GRD Griechische Drachmen ITL Italienische Lira NLG Niederländische Gulden AUD Australische Dollars CHF Schweizer Franken JPY Japanische Yen
Handelt es sich um eine feststehende
europäische Währungsbeziehung, nutzt das Modul lediglich seine internen
Tabellen und gibt sofort das Ergebnis zurück -- schließlich haben
die europäischen Teilnehmer an der Währungsunion feste Kurse ausgekartelt.
Liegt aber eine mit den Märkten fluktuierende
Beziehung vor, muss vor dem Aufruf von convert()
die Methode
updateRate()
ran, die mittels des Moduls Finance::Quote
den
aktuellen Umrechnungskurs von der Finanzseite des Anbieters Yahoo
abholt. Da dieser Netzzugriff eine Weile dauert und Währungen
für den Normalverbraucher nicht so stark wie Aktienkurse schwanken,
lassen sich die eingeholten Werte mit der Methode writeRatesFile()
in einer Cache-Datei abspeichern und von dort später wieder
mit readRatesFile()
laden.
Existiert noch keine Cache-Datei, weiss das Skript zunächst nicht, wie sich zum Beispiel österreichische Schillinge in Schweizer Franken umrechnen lassen:
$ ccon 100 ATS CHF Updating ... Please wait. 10.8509
Das nächste mal hingegen geht's sofort, da die Cache-Datei alle notwendigen Werte bereits enthält:
$ ccon 100 ATS CHF 10.8509
Verstreicht aber eine gewisse Zeitspanne, ist der Kurs veraltet und das Skript muss trotzdem wieder auf dem Internet nachfragen. Da Otto Normalverbraucher einmal täglich aufgefrischte Kurse genügen, geht das Skript nach folgendem Algorithmus vor: Morgens um zehn sollte der aktuelle Tageskurs vorliegen. Deshalb stellt es sicher, dass mindestens der 10-Uhr Kurs des letzten Werktages eingeholt wurde.
Listing ccon
zeigt die Implementierung. Die Zeilen 9 bis 11 setzen
mindestens perl
5.6.0 voraus und lassen es mit use warnings
und
use strict
gehörig mit der Peitsche knallen.
Zeile 13 zieht das schon erwähnte Modul Finance::Currency::Convert
hinzu, das seinerseits ein installiertes Finance::Quotes
voraussetzt.
Das in Zeile 14 hereingezogene Time::Local
liegt Perl-Distributionen
ab perl
5.6.0 bereits bei und wird später zu Datumsberechnungen
herangezogen.
01 #!/usr/bin/perl 02 ################################################## 03 # ccon -- Mike Schilli, 2001 (m@perlmeister.com) 04 # Convert currencies on the command line. 05 # Syntax: ccon amount source target 06 # [EUR,USD,DEM,GBP,ATS,ESP,FRF, 07 # FRF,GRD,ITL,NLG,AUD,CHF,JPY] 08 ################################################## 09 use 5.6.0; 10 use warnings; 11 use strict; 12 13 use Finance::Currency::Convert; 14 use Time::Local; 15 16 my $RATES_CACHE = "$ENV{HOME}/.currency"; 17 18 my($amount, @WAY) = @ARGV; 19 20 die "usage: $0 amount from to\n" 21 unless defined $ARGV[2]; 22 23 my $conv = Finance::Currency::Convert->new(); 24 25 # Cache-Datei setzen und lesen falls 26 # vorhanden 27 $conv->setRatesFile($RATES_CACHE); 28 29 if(!$conv->convert($amount, @WAY) or 30 update_recommended()) { 31 # Vom Internet nachladen 32 print "Updating ... Please wait.\n"; 33 $conv->updateRate(@WAY); 34 $conv->writeRatesFile(); 35 } 36 37 my $rate = $conv->convert($amount, @WAY); 38 39 die "Can't convert ", 40 join(' => ', @WAY) unless defined $rate; 41 42 print "$rate\n"; 43 44 ################################################## 45 sub update_recommended { 46 ################################################## 47 48 # nicht vorhanden => nachladen 49 return 1 unless -f $RATES_CACHE; 50 51 my $date = time(); 52 my @date = localtime($date); 53 54 $date -= 3600*24 if $date[2] < 10; 55 56 # Letzten Werktag suchen 57 { @date = localtime($date); 58 $date -= 3600*24, redo if 59 $date[6] == 0 or $date[6] == 6; 60 } 61 62 # Auf 10:00 setzen 63 @date[0..2] = (0, 0, 10); 64 65 # Zurück ins Sekundenformat 66 $date = timelocal(@date); 67 68 return (stat($RATES_CACHE))[9] < $date; 69 }
Den Namen der Cache-Datei des Skripts setzt der Skalar $RATES_CACHE
in Zeile 16 auf das unsichtbare .currency
im Heimatverzeichnis des
ausführenden Benutzers.
Zeile 18 sammelt die Kommandozeilenparameter ein. Die Signatur des
Skripts ist
ccon betrag ausgangswährung zielwährung
und deswegen liegen ab Zeile 18 der Betrag in $amount
und
die beiden Währungskürzel in den ersten zwei Elementen von
@WAY
.
Falls weniger als drei Kommandozeilenparameter vorliegen, ist
$ARGV[2]
undefiniert und Zeile 20/21 bricht das Programm mit einer
kurzen Bedienungsanleitung ab. Andernfalls erzeugt Zeile 23
ein neues Objekt vom Typ Finance::Currency::Convert
und legt eine
Referenz darauf in $conv
ab. Zeile 27 setzt den Namen der
Cache-Datei und liest die alten Kurse von dort, falls vorhanden, hinter
den Kulissen auch gleich ein.
Falls die convert
-Methode in Zeile 29 fehlschlägt oder die
weiter unten definierte Funktion update_recommended
einen wahren
Wert liefert, muss ccon
Daten aus dem Internet nachladen.
Da das einige Zeit dauern kann, gibt Zeile 32 eine kurze Meldung aus,
bevor Zeile 33 mit der updateRates
-Methode des
Finance::Currency::Convert
-Objekts Daten vom Internet holt.
Zeile 34 legt den neu gewonnenen Datensatz in der Cache-Datei ab.
Zeile 37 konvertiert schließlich die Währungen, basierend auf den verfügbaren Daten, und gibt sie aus. Zeile 39 bricht im Falle eines Konvertierungsproblems das Programm mit einer Fehlermeldung ab, Zeile 42 gibt im Erfolgsfall das Ergebnis aus.
Die ab Zeile 45 implementierte Funktion update_recommended()
rechnet aus, ob die aktuelle Cache-Datei gut genug ist oder ob
das Skript neue Daten vom Internet braucht. Es ermittelt den
Zeitpunkt 10:00 des letzten (oder aktuellen) Werktags und findet
heraus, ob die aktuelle Cache-Datei vor oder nach diesem
Zeitpunkt erzeugt wurde. Im ersten Fall gibt es 1
zurück, zum
Zeichen dafür, dass die aktuelle Cache-Datei eine Verjüngungskur
braucht. Im zweiten gibt's nichts neues und der von update_recommended()
zurückgegebene falsche Wert signalisiert dem Hauptprogramm, dass
die aktuelle Cache-Datei gut genug ist.
Hierzu ermittelt time()
in Zeile 51 die aktuelle Uhrzeit in Sekunden
seit 1970 und legt sie im Skalar $date
ab. Im Array @date
hingegen (völlig unabhängig von $date
übrigens) liegen später die
neun Datumsparameter, die localtime()
zurückliefert.
Falls es noch nicht 10 Uhr ist, fängt Zeile 54 erst gestern an
zu zählen.
Wenn der ermittelte Wochentag ein Samstag oder Sonntag ist, also
$date[6]
entweder 6
oder 0
enthält, setzt Zeile 58
um 24 Stunden zurück, springt zurück an den Anfang des Blocks in
Zeile 55 und versucht's nochmal. Sobald ein Werktag vorliegt, wird
der Block verlassen und Zeile 63 setzt die Uhrzeit auf 10:00 morgens.
Zeile 66 macht aus dem 9-Parameter-Array mit der Funktion
timelocal()
aus dem Modul Time::Local
aus der Standarddistribution
wieder eine Zeit in
Sekunden seit 1970. Zeile 68 holt mittels des 10. Feldes
der stat
-Funktion auf die Cache-Datei deren letztes Modifikationsdatum
hervor -- ebenfalls in Sekunden seit 1970. Falls die Datei nach
dem 10:00-Zeitpunkt verändert wurde, ist sie okay und update_recommended
gibt einen falschen Wert zurück
zum Zeichen dafür, dass keine Update erforderlich
ist. Andernfalls kommt ein wahrer Wert zurück, der im Hauptprogramm einen
Abgleich mit den Yahoo-Daten vom Internet auslöst.
Feiertage erkennt der Algorithmus nicht, es kann also sein, dass das
Skript einmal am Tag einen sinnlosen Versuch unternimmt, neue Daten
zu holen.
Die benötigten Module Finance::Quote
und Finance::Currency::Convert
installieren sich wie immer über eine CPAN-Shell:
perl -MCPAN -eshell cpan> install Finance::Quote cpan> install Finance::Currency::Convert
Wer bestimmte Umrechnungen häufig durchführt und Tipparbeit ersparen will, darf sich freilich Shell-Skripts definieren:
#!/bin/sh # Skript: d2e
ccon $1 USD EUR
Oder auch eine bash
-Funktion:
function d2e () { ccon $1 USD EUR }
In beiden Fällen ergibt ein anschließend von der Kommandozeile aufgerufenes
d2e 1
flugs 1.086248
, wenn der Dollar gerade auf 1.086248 Euro steht.
Rechnet fleißig um und gebt haufenweise Euros aus!
Michael Schilliarbeitet als Software-Engineer bei Yahoo! in Sunnyvale, Kalifornien. Er hat "Goto Perl 5" (deutsch) und "Perl Power" (englisch) für Addison-Wesley geschrieben und ist unter mschilli@perlmeister.com zu erreichen. Seine Homepage: http://perlmeister.com. |