![]() |
|
|||||
Da die Date-Klasse nicht ganz fehlerfrei und auch nicht internationalisiert war, wurden zwei neue Klassen, DateFormat und Calendar eingeführt. Calendar nimmt sich nun der Aufgabe von Date an, zwischen verschiedenen Datumsrepräsentationen und Zeitskalen zu konvertieren; DateFormat wird nun benutzt, um Datum-Zeichenketten zu zerlegen und für die Ausgabe zu formatieren. Datum-Formate sind ebenfalls abhängig vom Land, das in Java durch Locale-Objekte dargestellt wird, und von einer Zeitzone, die durch die Exemplare der Klasse TimeZone repräsentiert ist. 10.2.1 Zeitzonen durch die Klasse TimeZone repräsentiert
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Beispiel Nutzen wir für die Zeitrepräsentation Calendar-Objekte, so können wir mit setTimeZone() eine Zone fest zuweisen.
calendar.setTimeZone( TimeZone.getTimeZone("ECT") ); |
abstract class java.util.TimeZone |
| static TimeZone getDefault() Gibt die Zeitzone für die aktuelle (geographische) Umgebung zurück. |
| static String[] getAvailableIDs() Liefert alle der Bibliothek bekannten Abkürzungen für Zeitzonen. |
| static TimeZone getTimeZone( String ID ) Liefert die Zeitzone für eine gegebene Abkürzung. |
| Beispiel Um eine Aufzählung aller unterstützten Zeitzonen zu erhalten, geben wir alle Zeichenketten aus, die uns die statische Methode getAvailableIDs() liefert. |
import java.util.*; public class AllZones { public static void main( String args[] ) { String s[] = TimeZone.getAvailableIDs();
Arrays.sort( s ); for ( int i = 0; i < s.length; i++ ) System.out.println( s[i] ); } }
Arrays.sort(String[]) ist die statische Methode einer speziellen Array-Klasse, die das übergebene Feld sortiert. Unter Windows mit dem SDK Version 1.4 liefert das Programm 327 Zeitzonen von
ACT AET AGT ART AST Africa/Abidjan Africa/Accra
Pacific/Wake Pacific/Wallis SST UTC VST WET
Eine spezielle Unterklasse von TimeZone ist SimpleTimeZone. Um ein Exemplar für die mitteleuropäische Zeit zu konfigurieren, initialisieren wir das Objekt mit der gewünschten Zeitverschiebung gegenüber der GMT. Zusätzlich wird ein Kürzel für die Zeitzone als String übergeben. Danach stellen wir noch passend die Regeln für Anfang und Ende der Sommerzeit ein. Der Wechsel erfolgt am letzten Sonntag im März bzw. Oktober jeweils um 2 Uhr nachts.
Beispiel Eine SimpleTimeZone für Deutschland
SimpleTimeZone mez = new SimpleTimeZone( +1*60*60*1000, "ECT" ); mez.setStartRule( Calendar.MARCH, -1, Calendar.SUNDAY, 2*60*60*1000 ); mez.setEndRule( Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000 ); |
Wenn wir wiederum ein Calendar-Objekt mit der mitteleuropäischen Zeit als Grundlage versehen wollen, schreiben wir:
Calendar cal = GregorianCalendar.getInstance( mez );
Programme der ersten Generation konnten nur mit fest verdrahteten Landessprachen und landesüblichen Bezeichnungen umgehen. Daraus ergaben sich natürlich vielfältige Probleme. Mehrsprachige Programme mussten aufwendig programmiert werden, damit sie unter mehreren Sprachen liefen. Es ergaben sich bereits Probleme dadurch, dass unterschiedliche Zeichenkodierungen verwendet wurden. Dies wurde aber durch Unicode umgangen. Es bleibt das Problem, dass sprachabhängige Zeichenketten, wie alle anderen Zeichenketten auch, überall im Programmtext verteilt sind. Eine nachträgliche Sprachanpassung wird schwer. Java bietet hier eine Lösung an. Einmal durch die Definition einer Sprache und einmal durch die Möglichkeit, sprachenabhängige Teile in Ressourcen-Dateien auszulagern.
Eine Sprache (Locale) ist in Java eine Verbindung aus gesprochener Sprache und geografischer Region. Jede dieser sprachspezifischen Eigenschaften ist in einem speziellen Objekt gekapselt, das als Exemplar der Klasse Locale realisiert ist. Die Sprache und die Region müssen getrennt werden, denn nicht immer gibt eine Region oder ein Land die Sprache eindeutig vor. Für die Umgebung in dem französisch sprechenden Teil von Kanada ist etwa der Kalender von Quebec relevant, und der unterscheidet sich von einem englischen Kalender.
Beispiel Sprach-Objekte werden immer mit dem Namen der Sprache und optional mit dem Namen des Landes bzw. einer Region erzeugt. Im Konstruktor der Klasse Locale werden dann Länderabkürzungen angegeben. Etwa für ein Sprach-Objekt für England oder Frankreich.
Locale greatBritain = new Locale( "en", "GB" ); Locale french = new Locale( "fr" ); |
Im zweiten Beispiel ist uns das Land egal. Wir haben einfach nur die Sprache Französisch ausgewählt, egal auf welchem Teil der Welt. Die Sprachen sind durch Zwei-Buchstabenkürzel aus dem ISO-639 Code identifiziert und die Ländernamen sind Zwei-Buchstabenkürzel, die im ISO-3166 beschrieben sind.
final class java.util.Locale |
| Locale( String language ) |
Erzeugt ein neues Locale-Objekt für die Sprache language.
| Locale( String language, String country ) |
Erzeugt ein Locale-Objekt für language und das Land country.
| public Locale( String language, String country, String variant ) |
Erzeugt ein Locale-Objekt für language und das Land country in der Variante variant. variant ist eine herstellerabhängiges Angabe, etwa WIN für Windows, MAC für Macintosh und POSIX für POSIX.
Da die Codes nicht immer so intuitiv sind, besitzt die Locale-Klasse ein paar Konstanten für häufig auftretende Länder und Sprachen. Für ein Locale-Objekt für Great Britain kann anstelle von new Locale("en","GB") auch Locale.UK Verwendung finden. Unter den Konstanten sind: CANADA, CANADA_FRENCH, CHINA, CHINESE, ENGLISH, FRANCE, FRENCH, GERMAN, GERMANY, ITALIAN, ITALY, JAPAN, JAPANESE, KOREA, KOREAN, PRC, SIMPLIFIED_CHINESE, TAIWAN, TRADITIONAL_CHINESE, UK, US. Im Quellcode der Klasse Locale sind dazu einfach die entsprechenden Länderkürzel als Namen von Konstanten definiert.
static public final Locale FRANCE = new Locale("fr","FR",""); static public final Locale GERMANY = new Locale("de","DE","");
Locale-Objekte lassen sich fragen, wie ihre Sprache heißt, die sie repräsentieren. Dazu bietet das Locale-Objekt eine Reihe von Methoden an:
final class Locale |
| String getCountry() |
Liefert das Länderkürzel nach dem ISO 3166 Zwei-Buchstaben-Code.
| String getLanguage() |
Liefert das Kürzel der Sprache im ISO 639 Code.
| String getVariant() |
Liefert das Kürzel der Variante.
| final String getDisplayCountry() |
Liefert ein Kürzel des Landes für Bildschirmausgaben.
| final String getDisplayLanguage() |
Liefert ein Kürzel der Sprache für Bildschirmausgaben.
| final String getDisplayName() |
Liefert den Namen der Einstellungen.
| final String getDisplayVariant() |
Liefert den Namen der Variante.
| String getISO3Country() |
Liefert die ISO-Abkürzung des Landes dieser Einstellungen und löst eine ExMissingResourceException aus, wenn die ISO-Abkürzung nicht verfügbar ist.
| String getISO3Language() |
Liefert die ISO-Abkürzung der Sprache dieser Einstellungen und löst eine MissingResourceException aus, wenn die ISO-Abkürzung nicht verfügbar ist.
| Beispiel Die folgende Applikation gibt alle gefundenen Locale-Objekte aus. Wir erkennen an der Ausgabe auch die Unterschiede der Funktionen. |
import java.util.*; public class AllLocales { public static void main( String args[] ) { Locale locs[] = Locale.getAvailableLocales(); for ( int i = 0; i < locs.length; i++ ) { Locale l = locs[i]; System.out.print( l.getCountry() + ", " ); System.out.print( l.getLanguage() + ", " ); System.out.print( l.getVariant() + ", " ); System.out.print( l.getDisplayName() + ", " ); System.out.print( l.getDisplayCountry() + ", " ); System.out.print( l.getDisplayLanguage() + ", " ); System.out.print( l.getDisplayName() + ", " ); System.out.print( l.getDisplayVariant() + ", " ); System.out.print( l.getISO3Country() + ", " ); System.out.println( l.getISO3Language() ); } } }
Ein Ausschnitt der Ausgabe. Bemerkenswert ist, dass einige Angaben nicht gefüllt sind.
, en, , Englisch, , Englisch, Englisch, , , eng US, en, , Englisch (Vereinigte Staaten von Amerika), Vereinigte Staaten von Amerika, Englisch, Englisch (Vereinigte Staaten von Amerika), , USA, eng , ar, , Arabisch, , Arabisch, Arabisch, , , ara AE, ar, , Arabisch (Vereinigte Arabische Emirate), Vereinigte Arabische Emirate, Arabisch, Arabisch (Vereinigte Arabische Emirate), , ARE, ara BH, ar, , Arabisch (Bahrain), Bahrain, Arabisch, Arabisch (Bahrain), , BHR, ara ... , zh, , Chinesisch, , Chinesisch, Chinesisch, , , zho CN, zh, , Chinesisch (China), China, Chinesisch, Chinesisch (China), , CHN, zho HK, zh, , Chinesisch (Hongkong), Hongkong, Chinesisch, Chinesisch (Hongkong), , HKG, zho TW, zh, , Chinesisch (Taiwan), Taiwan, Chinesisch, Chinesisch (Taiwan), , TWN, zho
Sollen Java-Programme sprachunabhängig gestaltet werden, müssen alle Zeichenketten einer Landessprache durch symbolische Namen, wie Variablen, ersetzt werden. Wenn das Programm später eine Zeichenkette nutzen will, greift es auf die Variable zu, und diese soll dann die entsprechende Übersetzung enthalten. Die Verbindung zwischen den symbolischen Namen und den landessprachlichen Texten erfolgt in Java mithilfe der Klasse ResourceBundle. Dazu speichert ein ResourceBundle alle Programm-relevanten Texte und Informationen für ein spezielles Land. In einer Datei werden die Variablennamen als Schlüssel und die landesabhängigen Zeichenketten als Werte gehalten. Der Aufbau eines ResourceBundle erinnert uns dabei stark an eine Property-Datei. Wir wollen daher mit dem Aufbau dieser Property-Datei beginnen und definieren eine Variable Hello. Da wir die Sprachen Englisch und Deutsch unterstützen wollen, legen wir zwei Dateien an. Die Dateinamen haben dabei einen speziellen Aufbau. Sie setzen sich aus dem Namen des ResourceBundle, einem _, einer Landeskennung und der Dateiendung properties zusammen. Da wir unser ResourceBundle »HelloWorld« nennen wollen und die Ländercodes für England en und für Deutschland de sind, ergeben sich die folgenden Dateien:
Listing 10.3 HelloWorld_en.properties# HelloWorld_en.properties Hello=Hello World.Listing 10.4 HelloWorld_de.properties
# HelloWorld_de.properties Hello=Hallo Welt.
Kommentare können mit einer Raute beginnen.
Als Nächstes kann das Programm folgen, welches die ResourceBundle-Dateien verwendet. Wir benötigen dazu eine Objekt der Klasse ResourceBundle, welches wir über eine Fabrik-Methode ResourceBundle.getBundle(name) bekommen. name ist dabei der Name des ResourceBundle. Die Methode wählt dabei automatisch auf Grund der eingestellten Landessprache die passende Datei. Mit einer Referenz auf das aktuelle ResourceBundle-Objekte können wir mit Hilfe der Methode getString() auf die landesspezifische Meldung über einem Schlüssel zugreifen.
| Beispiel Bezüglich der beiden obigen Ressource-Dateien mit der Variablen Hello setzt sich das Programm einfach zusammen. |
import java.util.*; //java -Duser.language=en InternationalHelloWorld //Hello World. public class InternationalHelloWorld { public static void main( String args[] ) { String baseName = "HelloWorld"; try { ResourceBundle bundle = ResourceBundle.getBundle( baseName ); System.out.println( bundle.getString("Hello") ); } catch ( MissingResourceException e ) { System.err.println( e ); } } }
Die Dateinamen für die jeweiligen ResourceBundle-Objekte können sehr variabel zusammengesetzt werden. Die nachfolgenden Bildungsgesetze verwendet die Java-Bibliothek:
bundleName_localeLanguage_localeCountry_localeVariant bundleName_localeLanguage_localeCountry bundleName_localeLanguage bundleName_defaultLanguage_defaultCountry_defaultVariant bundleName_defaultLanguage_defaultCountry bundleName_defaultLanguage bundleName
Die Suchreihenfolge ist dabei wie angegeben. Es können auch mehrere Resource-Dateien angegeben werden, die dann der Reihe nach durchlaufen werden, sodass dadurch Werte überschrieben werden können.
|
Die ältere Klasse Date ist durch die Aufgabenverteilung auf die Klassen DateFormat und Calendar sehr schlank. Ein Exemplar der Klasse Date verwaltet ein besonderes Datum oder eine bestimmte Zeit; die Zeitgenauigkeit beträgt eine Millisekunde.
Mit der Date-Klasse können keine Datum-Objekte für Zeitpunkte vor dem 1.1.1970 erzeugt werden. Zwei Konstruktoren der Klasse bleiben uns:
| Der Standard-Konstruktor, welcher ein Datum-Objekt mit der augenblicklichen Zeit erzeugt. Die gegenwärtige Zeit erfragt dieser Konstruktor mittels System.currentTimeMillis(). |
| Der zweite Konstruktor bekommt eine Zeitangabe in Millisekunden seit dem Stichtag 1.1.1970 und initialisiert daraufhin das Objekt. Mit verschiedenen Methoden kann nun die Zeit verändert, ausgelesen oder in der zeitlichen Abfolge verglichen werden. |
class java.util.Date |
| Date() Erzeugt ein Datum-Objekt und initialisiert es mit der Zeit, die bei der Erzeugung gelesen wurde. |
| Date( long ) Erzeugt ein Datum-Objekt und initialisiert es mit der übergebenen Anzahl von Millisekunden seit dem 1. Januar 1970, 00:00:00 GMT. |
| long getTime() Liefert die Anzahl der Millisekunden nach dem 1. Januar 1970, 00:00:00 GMT zurück. |
| void setTime( long ) Setzt wie der Konstruktor die Anzahl Millisekunden des Datum-Objekts neu. Wurde ein Datum-Objekt einmal erzeugt, dann ändert sich dies durch das Objekt repräsentierte Datum natürlich nicht mehr automatisch. Um also die Zeit wieder aktuell zu setzen, kann today.setTime( new java.util.Date() ) verwendet werden. |
| boolean before( Date ) boolean after( Date ) Testet, ob das eigene Datum vor oder nach dem Datum des Parameters liegt. true, wenn davor oder danach, false sonst. |
| boolean equals( Object ) Testet die Datum-Objekte auf Gleichheit. true, wenn getTime() für beide den gleichen Wert ergibt und der Parameter nicht null ist. |
| int compareTo( Date ) Vergleicht zwei Datum-Objekte und gibt null zurück, falls beide die gleiche Zeit repräsentieren. Der Rückgabewert ist kleiner Null, falls das Datum des aufrufenden Exemplars vor dem Datum von anotherDate ist, und größer Null sonst. |
| int compareTo( Object ) Ist das übergebene Objekt vom Typ Date, dann verhält sich die Funktion wie compareTo(). Andernfalls wirft die Methode, falls der Parameter sich nicht als Date verhalten kann, eine ClassCastException. |
| toString() Gibt eine Repräsentation des Datums aus. |
| Beispiel Mit der toString()-Funktion können wir ein minimales Zeit-Anzeige-Programm schreiben. Wir rufen den Standard-Konstruktor auf und geben dann die Zeit aus. Natürlich wird von der println()-Funktion toString() aufgerufen. |
import java.util.Date; class MiniClock { public static void main( String args[] ) { System.out.println( new Date() ); } }
Die Methode getTime() der Klasse Date gibt einen Zeitpunkt als vergangene Millisekunden ab einem festen Stichtag zurück. Damit kann die Differenz zweier Datum-Objekte auf Millisekunden-Basis errechnet werden und diese kann dann zur groben Abschätzung von Ausführungszeiten für Programme dienen.
Listing 10.7 Profiling.javaimport java.util.Date; final class Loop { static int loop1( int i ) { return i * i; } int loop2( int i ) { return i * i; } } class Profiling { public synchronized static void main( String args[] ) { Loop loop = new Loop(); int MAX = 100000000; // use static function Date start1 = new Date(); for ( int i = MAX; i-- > 0; ) Loop.loop1( i ); long time1 = new Date().getTime() – start1.getTime(); // use dynamic function Date start2 = new Date(); for ( int i = MAX; i-- > 0; ) loop.loop2( i ); long time2 = new Date().getTime() – start1.getTime(); System.out.println( "Used time static: " + time1 ); System.out.println( "Used time dynamic: " + time2 ); } }
Wird das Programm gestartet, so bekomme ich auf meinem Rechner (AMD Athlon 1,2 GHz, Java SDK 1.4b2) die nachstehende Ausgabe.
Used time static: 641 Used time dynamic: 1232
| Tipp Dieses Beispiel zeigt, an welchen Stellen ein Programmierer optimieren kann. Wenn es auf Geschwindigkeit ankommt, sollte der Einsatz von statischen Methoden in Erwägung gezogen werden und dynamische Bindungen vermieden werden. Leider macht das unter Umständen den Entwurf kaputt bzw. das Programm später schwerer änderbar. |
Calendar ist eine abstrakte Klasse, die zur Konvertierung zwischen verschiedenen Datum-Formaten eingesetzt wird. Über Methoden von Calendar ist es möglich, Datum und Uhrzeit in den einzelnen Komponenten wie Jahr, Monat, Tag, Minute, Sekunde zu verändern. Da Calendar eine abstrakte Basisklasse ist, können erst Unterklassen die Attribute und Methoden richtig benutzen. Unter dem JDK ist bisher nur die Unterklasse GregorianC alendar implementiert, deren Exemplare Daten und Zeitpunkte gemäß dem gregorianischen Kalender verkörpern.
Die Klasse Calendar besitzt nur wenige statische Funktionen, die sofort genutzt werden können. Eine Klassen- und Fabrik-Methode ist getInstance(), um ein benutzbares Objekt zu bekommen. Die Methode gibt ein Objekt vom Typ GregorianCalendar zurück und die Werte sind mit der aktuellen Zeit gesetzt.
|
abstract class java.util.Calendar |
| static Calendar getInstance() Liefert einen Calendar in der Ausprägung von GregorianCalendar mit der eingestellten Zeitzone und Lokalisierung zurück. |
Neben der parameterlosen Variante von getInstance() bestehen drei weitere Varianten, denen ein TimeZone-Objekt und Locale-Objekt mit übergeben werden können. Damit kann dann der Kalender auf eine spezielle Zeitzone und einen Landstrich zugeschnitten werden. Da ein Kalender unter verschiedenen Orten installiert sein kann, gibt getAvailableLocales() eine Aufzählung von Locale-Objekten zurück.
Die abstrakte Klasse Calendar wird durch die Klasse GregorianCalendar implementiert. In der jetzigen Implementierung deckt diese Klasse vom Jahr 4716 vor unserer Zeitrechnung bis zum Jahre 5.000.000 alles korrekt ab. Sieben Konstruktoren stehen zur Verfügung, und vier schauen wir uns an:
class java.util.GregorianCalendar |
| GregorianCalendar() Erzeugt ein standardmäßiges GregorianCalendar-Objekt mit der aktuellen Zeit in der voreingestellten Zeitzone und Lokalisierung. |
| GregorianCalendar( int year, int month, int date ) Erzeugt ein GregorianCalendar-Objekt in der voreingestellten Zeitzone und Lokalisierung. Das Datum wird durch Jahr, Monat (der zwischen 0 und 11 und nicht zwischen 1 und 12 liegt) und Tag festgelegt. |
| GregorianCalendar( int year, int month, int date, int hour, int minute ) Erzeugt ein GregorianCalendar-Objekt in der voreingestellten Zeitzone und Lokalisierung. Das Datum wird durch Jahr, Monat (0 <= month <= 11 ), Tag, Stunde und Minute festgelegt. |
| GregorianCalendar( int year, int month, int date, int hour, int minute, int second ) Erzeugt ein GregorianCalendar-Objekt in der voreingestellten Zeitzone und Lokalisierung. Das Datum wird durch Jahr, Monat (0 <= month <= 11), Tag, Stunde, Minute und Sekunde festgelegt. |
Neben den hier aufgeführten Konstruktoren gibt es noch weitere, die es erlauben, die Zeitzone und Lokalisierung zu ändern. Standardmäßig eingestellt ist die lokale Zeitzone und die aktuelle Lokalisierung. Ist einer der Parameter im falschen Bereich, so wird eine IllegalArgumentException ausgelöst. Damit bei der 0 und 1 Anfrageprobleme vermieden werden, sollten die Konstanten JANUARY (0), FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER (11) verwendet werden. Die spezielle Variable UNDECIMBER (12) steht für den dreizehnten Monat, der etwa bei einem Mondkalender anzutreffen ist.
Leider haben wir mit dem Standard-Konstruktor von GregorianCalendar ein kleines Problem. Zur Klärung schauen wir uns die Implementierung einmal genauer an:
public GregorianCalendar() { this( TimeZone.getDefault(), Locale.getDefault() ); }
Wird der gregorianische Kalender ohne Zeitzonenangabe konstruiert, wird die statische Methode getDefault() von der Klasse TimeZone aufgerufen. In der Implementierung von getDefault() finden wir dann Folgendes:
ID = System.getProperty( "user.timezone", "GMT" );
In den System-Eigenschaften wird also nach user.timezone gefragt und falls dieser Eintrag dann nicht existiert, wird die Zeitzone GMT angenommen. Da diese Einstellung bei den meisten Rechnern nicht auf (European Central Time, kurz ECT) steht – wie es bei uns in Deutschland sein sollte – gehen alle Zeitangaben eine Stunde nach. Um dieses Problem zu beheben, sollte die korrekte Zeitzone mit dem Konstruktor GregorianCalendar(TimeZone) oder mit der Methode setTimeZone()aus der Klasse Calendar eingestellt werden.
calendar = new GregorianCalendar(); calendar.setTimeZone( TimeZone.getTimeZone("ECT") );
| Hinweis Natürlich verfehlt dies total seinen Zweck, da wir die Zeitzone nicht von Hand setzen sollten. Aber leider funktioniert es ohne explizites Setzen auf einigen Computern nicht. |
Das Abfragen und Setzen von Elementen des Datums vom gregorianischen Kalender erfolgt mit den überladenen Methoden set() und get(). Beide erwarten als ersten Parameter einen Feldbezeichner – eine Konstante aus der Klasse Calendar –, der angibt, auf welches Datum- bzw. Zeit-Feld zugegriffen werden soll. Die get-Methode liefert den Inhalt des angegebenen Feldes und set schreibt den als zweiten Parameter übergebenen Wert in das Feld. Die nachfolgende Tabelle gibt eine Übersicht der Feldbezeichner und ihrer Wertbereiche.
abstract class java.util.Calendar |
| Feldbezeichner Calendar.* |
Minimalwert | Maximalwert | Erklärung |
| 0 (BC) | 1 (AD) | Datum vor oder nach Chr. | |
| 1 | 5000000 | Jahr | |
| 0 | 11 | MonatMonat (nicht von 1-12!) | |
| DAY_OF_MONTH alternativ DATE | 1 | 31 | Tag |
| 1 | 54 | Woche | |
| 1 | 6 | Woche des Monats | |
| 1 | 366 | Tag des Jahres | |
| 1 | 7 | Tag der Woche (1= Sonntag, 7 = Samstag) |
|
| -1 | 6 | Tag der Woche im Monat | |
| 0 | 12 | Stunde von 12 | |
| 0 | 23 | Stunde von 24 | |
| 0 | 59 | Minute | |
| 0 | 59 | Sekunden | |
| 0 | 999 | Millisekunden | |
| 0 | 1 | vor 12, nach 12 | |
| -12*60*60*1000 | 12*60*60*1000 | Zeitzonenabweichung in Millisekunden | |
| 0 | 1*60*60*1000 | Sommerzeitabweichung in Millisekunden |
Nun können wir mit den Varianten von set() die Felder setzen und mit get() wieder reinholen. Beachtenswert ist der Anfang der Monate mit 0 und der Anfang der Wochentage mit 1 (SUNDAY), 2 (MONDAY), ..., 7 (SATURDAY) -Konstanten der Klasse Calendar stehen in Klammern.
abstract class java.util.Calendar |
| final void set( int field, int value ) Setzt das Feld field mit dem Wert value. |
| final void set( int year, int month, int date ) Setzt die Werte für Jahr, Monat und Tag. |
| final void set( int year, int month, int date, int hour, int minute ) Setzt die Werte für Jahr, Monat, Tag, Stunde und Minute. |
| final void set( int year, int month, int date, int hour, int minute, int second) Setzt die Werte für Jahr, Monat, Tag, Stunde und Minute und Sekunde. |
| final int get( int field ) Liefert den Wert für field. |
Die Methoden zum gleichzeitigen Setzen von Jahr, Monat und Tag usw. sind nur Hilfsfunktionen und ihre Implementierung ist einfach:
public final void set(int year, int month, int date) { set(YEAR, year); set(MONTH, month); set(DATE, date); }
Leider ist es mit einem einfachen set() zum Setzen der Feldwerte nicht getan.1
Ein weiteres Problem betrifft die Konsistenz zwischen den verschiedenen internen Datumsdarstellungen eines Calendar-Exemplars. Hier müssen wir etwas tricksen und durch den Aufruf von setTime(getTime()) die Darstellung in Millisekunden und die verschiedenen anderen Feldwerte abgleichen. Bevor wir also mit get() die Werte wieder abfragen, schreiben wir die Zeile:
calendar.setTime( calendar.getTime() );
Wir wollen im folgenden Beispiel ein GregorianCalendar-Objekt erzeugen und mit einer selbst geschriebenen Funktion printCalendar() wichtige Felder ausgeben. Da die Daten nicht bearbeitet werden, handelt es sich um das aktuelle Tagesdatum. Anschließend manipulieren wir mit den set()-Methoden das Objekt und setzen es auf das Geburtsdatum des Autors.
Listing 10.8 DateDemo.javaimport java.util.*; public class DateDemo { public static void main( String args[] ) { GregorianCalendar cal = new GregorianCalendar(); cal.setTimeZone(TimeZone.getTimeZone("ECT")); cal.setTime(cal.getTime()); printCalendar( cal ); cal.set( Calendar.DATE, 12 ); cal.set( Calendar.MONTH, Calendar.MARCH ); cal.set( Calendar.YEAR, 1973 ); printCalendar( cal ); } public static void printCalendar( Calendar cal ) { String dayOfWeek = (new String[]{ "Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnertag", "Freitag", "Samstag"}) [cal.get(Calendar.DAY_OF_WEEK)-1]; // Sonntag = 1 System.out.println( dayOfWeek + ", " + cal.get(Calendar.DATE) + "." + (cal.get(Calendar.MONTH)+1) + "." + cal.get(Calendar.YEAR) + ", " + cal.get(Calendar.HOUR_OF_DAY) + ":" + out(cal.get(Calendar.MINUTE)) + ":" + out(cal.get(Calendar.SECOND)) + " und " + cal.get(Calendar.MILLISECOND) + " ms" ); System.out.print( "Es ist die "+ cal.get(Calendar.WEEK_OF_YEAR) + ". Woche im Jahr und " ); System.out.println( cal.get(Calendar.WEEK_OF_MONTH) + ". Woche im Monat\n" ); } public static String out( int i ) { return ( i >= 10 ) ? Integer.toString(i) : "0"+i; } }
Die Ausgabe des Programms lautet etwa so:
Dienstag, 19.6.2001, 21:52:13 und 816 ms Es ist die 25. Woche im Jahr und 3. Woche im Monat Montag, 12.3.1973, 21:52:13 und 816 ms Es ist die 11. Woche im Jahr und 3. Woche im Monat
Da die Ausgabe auf diese Art und Weise nicht besonders komfortabel ist, werden wir mit DateFormat eine Klasse kennen lernen, die die Formatierung der Ausgabe vereinfacht.
Diese Frage lässt sich einfach mit getActualMaximum() herausfinden. Als Parameter wird der Methode ein Feldbezeichner aus der Klasse Calendar übermittelt, dessen Maximum sie dann bestimmt.
Das folgende Programm listet alle Monate des gregorianischen Kalenders auf. Da dieser genau 12 Monate umfasst, können wir eine feste Schleife programmieren. Für einen Mondkalender sähe dies etwas anders aus. Den Beweis, dass das Programm korrekt funktioniert, sollten wir mit einem Abzählen der Fingerknochen führen.
Listing 10.9 Fingerknochen.javaimport java.util.*; class Fingerknochen { public static void main( String args[] ) { GregorianCalendar cal = new GregorianCalendar(); System.out.println( cal.getTime() ); for ( int month=Calendar.JANUARY; month<=Calendar.DECEMBER; month++ ) { cal.set( Calendar.MONTH, month ); System.out.println( (month+1) + " : " + cal.getActualMaximum(Calendar.DAY_OF_MONTH) ); } } }
Nachdem wir nun eine Unterklasse von Calendar, nämlich GregorianCalendar, dazu benutzt haben, Datumswerte zu verwalten, wollen wir nun untersuchen, wie eine Formatierungsklasse dazu landestypische Ausgaben erzeugt.
Bevor wir mit den Methoden der Calendar- bzw. GregorianCalendar-Klasse weitermachen, wollen wir eine neue Klasse kennen lernen, die die Ausgabe und das Einlesen der Datum-Felder übernimmt. Es handelt sich dabei um die Klasse DateFormat. Da