Galileo Computing < openbook >
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.


Java ist auch eine Insel von Christian Ullenboom
Buch: Java ist auch eine Insel (Galileo Computing)
gp Kapitel 10 Raum und Zeit
gp 10.1 Greenwich Mean Time (GMT)
gp 10.2 Wichtige Datum-Klassen im Überblick
gp 10.3 Zeitzonen und Sprachen der Länder
gp 10.3.1 Zeitzonen durch die Klasse TimeZone repräsentieren
gp 10.4 Sprachen der Länder
gp 10.4.1 Sprachen in Java über Locale-Objekte
gp 10.5 Einfache Übersetzung durch ResourceBundle-Objekte
gp 10.6 Die Klasse Date
gp 10.6.1 Objekte erzeugen und Methoden nutzen
gp 10.7 Calendar und GregorianCalendar
gp 10.7.1 Die abstrakte Klasse Calendar
gp 10.7.2 Der gregorianische Kalender
gp 10.8 Formatieren der Datumsangaben
gp 10.8.1 Mit DateFormat und SimpleDateFormat formatieren
gp 10.8.2 Parsen von Datumswerten
gp 10.8.3 Parsen und Formatieren ab bestimmten Positionen


Galileo Computing

10.8 Formatieren der Datumsangabendowntop

Nachdem wir eine Unterklasse von Calendar, nämlich GregorianCalendar, dazu benutzt haben, Datumswerte zu verwalten, wollen wir nun untersuchen, wie eine Formatierungsklasse dazu landestypische Ausgaben erzeugt. Unsere eigenen Ausgaben haben wir ja schon gemacht, doch es geht noch einfacher; die Java-Bibliothek kümmert sich selbstständig um die richtigen Ausgaben.


Galileo Computing

10.8.1 Mit DateFormat und SimpleDateFormat formatierendowntop

Eine Klasse, die die Ausgabe und das Einlesen der Datum-Felder übernimmt, ist DateFormat. Da DateFormat abstrakt ist, wird erst eine implementierende Klasse einsatzbereit sein. Natürlich liegt eine solche Klasse auch vor: SimpleDateFormat. Die Klasse bietet reichhaltig Methoden zur Zerlegung von Datum-Zeichenketten sowie Methoden zur Ausgabe unter verschiedenen Sprachen und Formatierungen an.

Abbildung
Hier klicken, um das Bild zu Vergrößern


Beispiel Ausgabe des Datums ohne zusätzliche Formatierungsanweisungen:

Listing 10.10 DateFormater.java

import java.util.*;
import java.text.*;
public class DateFormater
{
  public static void main( String args[] )
  {
    Calendar cal = new GregorianCalendar( TimeZone.getTimeZone("ECT") );
    SimpleDateFormat formater = new SimpleDateFormat();
    System.out.println( formater.format( cal.getTime() ) ); // 02.03.03 23:41
  }
}

Um das Datum zu formatieren, müssen wir zunächst ein Exemplar von SimpleDateFormat erzeugen. Dieses bekommt dann eventuell Formatierungsanweisungen (über eine andere Methode oder über einen weiteren Konstruktor) und formatiert dann mit der format()-Funktion das Datum. Die format()-Funktion gibt einen String zurück. Die Ausgabe ist nicht ganz Jahr-20001-fest5.


class java.text.SimpleDateFormat
extends DateFormat

gp SimpleDateFormat()
Erzeugt ein neues SimpleDateFormat-Objekt in der eingestellten Sprache.

abstract class java.text.DateFormat
extends Format
implements Cloneable

gp final String format( Date date )
Formatiert das Datum in einen Datum/Zeit-String.

Vorgefertigte Formatierungen

Wir haben im vorherigen Beispiel gesehen, dass das Ausgabeformat auf Monat, Tag, Jahr, Leerzeichen, Stunde, Minute festgelegt ist. Nun bietet die DateFormat-Klasse aber auch die statischen Methoden getDateInstance(), getTimeInstance() und getDateTimeInstance() mit den möglichen Parametern DateFormat.SHORT, DateFormat.MEDIUM, DateFormat.LONG oder DateFormat.FULL an, die die Zeit beziehungsweise das Datum auf vier Arten formatieren:


Konstante Beispiel für Datum Beispiel für Zeit

SHORT

29.9.97 21:51

MEDIUM

29.9.1997 21:54:46

LONG

19. September 1997 21:53:20 GMT+02:00

FULL

Montag, 29. September 1997 21.53 Uhr GMT+02:00

Tabelle 10.3 Konstanten aus DateFormat und ihre Wirkung

Verschiedene statische Funktionen von DateFormat erzeugen direkt ein Formatier-Objekt:


abstract class java.text.DateFormat
extends Format
implements Cloneable

gp static final DateFormat getDateInstance()
static final DateFormat getTimeInstance()
static final DateFormat getDateTimeInstance()
Liefert einen Datum/Zeit-Formatierer mit dem vorgegebenen Stil aus der Standardumgebung.
gp static final DateFormat getDateInstance( int dateStyle )
static final DateFormat getTimeInstance( int style )
Liefert einen Datum/Zeit-Formatierer mit dem Stil style und der Standardsprache.
gp static final DateFormat getDateInstance( int style, Locale aLocale )
static final DateFormat getTimeInstance( int style, Locale aLocale )
Liefert einen Datum/Zeit-Formatierer mit dem Stil style und der Sprache aLocale.
gp static final DateFormat getDateTimeInstance( int dateStyle, int timeStyle )
Gibt einen Datum/Zeit-Formatierer für die gesetzte Sprache im angegebenen Formatierungsstil zurück.
gp static final DateFormat getDateTimeInstance( int dateStyle, int timeStyle,
Locale aLocale )
Gibt einen Datum/Zeit-Formatierer für die Sprache aLocale im angegebenen Formatierungsstil zurück.

Abbildung
Hier klicken, um das Bild zu Vergrößern

Beispiel mit Sprachen

Um ein Datum oder eine Zeitangabe für unterschiedliche Sprachen aufzubereiten, können wir mit der getDateInstance()-Funktion auch ein DateFormat-Objekt für eine bestimmte Sprachumgebung bekommen. Wir haben gesehen, dass unter Locale für einige Sprachen Konstanten vordefiniert sind. Nicht alle Sprachen erzeugen gültige Datumsausgaben.

Um für das französische Datum und die Zeit einen Formatierer zu bekommen, schreiben wir einfach:

DateFormat df = DateFormat.getDateInstance( Locale.FRANCE );

Nun wollen wir das individuelle Formatieren in einem Beispiel zusammenbauen. Das Programm erzeugt die Ausgabe für Deutschland und anschließend für Italien.

Listing 10.11 SimpleDateFormater.java

import java.util.*;
import java.text.*;
public class SimpleDateFormater
{
  public static void main( String args[] )
  {
    Calendar cal = new GregorianCalendar( TimeZone.getTimeZone("ECT") );
    DateFormat formater;
    formater = DateFormat.getDateTimeInstance(
     DateFormat.FULL, DateFormat.MEDIUM );
    System.out.println( formater.format( cal.getTime() ) );
    formater = DateFormat.getDateTimeInstance(
        DateFormat.FULL, DateFormat.MEDIUM, Locale.ITALY );
    System.out.println( formater.format( cal.getTime() ) );
  }
}

Die Ausgabe ist Folgende:

Sonntag, 2. März 2003 23:45:08
domenica 2 marzo 2003 23.45.08

Eine noch individuellere Ausgabe

Um das Ausgabeformat individueller anzupassen, kann ein Formatierungs-String die Ausgabe anpassen. Diese Formatierungsanweisung, in der alle ASCII-Zeichen eine bestimmte Bedeutung haben, wird entweder dem Konstruktor der Klasse SimpleDateFormat übergeben oder kann nachträglich mit der applyPattern()-Methode geändert werden. Nachfolgende Tabelle zeigt die erlaubten Symbole mit ihren Sonderbedeutungen. Mehrfach wiederholte Zeichen werden, wenn möglich, durch die Langform der jeweiligen Angabe ersetzt. Diese Symbole sind sprachunabhängig.


Symbol Bedeutung Präsentation Beispiel

G

Ära Text AD

y

Jahr Nummer 1998

M

Monat im Jahr Nummer 7

MM

Monat im Jahr mit 0 Nummer 07

MMM

Monat im Jahr kurz Text Sep

MMMM

Monat im Jahr lang Text September

d

Tag im Monat Nummer 26

h

Stunde (1-12) Nummer 9

H

Stunde am Tag (0-23) Nummer 0

m

Minute der Stunde Nummer 13

s

Sekunde der Minute Nummer 22

S

Millisekunde Nummer 257

E

Tag der Woche kurz Text Mi

EEEE

Tag der Woche lang Text Mittwoch

D

Tag im Jahr Nummer 304

F

Tag der Woche im Monat Nummer 3

w

Woche im Jahr Nummer 12

W

Woche im Monat Nummer 3

a

am- und pm-Text Text AM

k

Stunde am Tag (1-24) Nummer 24

K

Stunde (0-11) Nummer 0

z

Zeitzone Text GMT+02:00

'

Zeichen für Text Trennzeichen Hallo Welt

''

einzelnes Hochkomma Literal '

Tabelle 10.4 Symbole im Formatierungs-String zur Steuerung der Ausgabe


class java.text.SimpleDateFormat
extends DateFormat

gp SimpleDateFormat()
Erzeugt ein neues SimpleDateFormat-Objekt in der eingestellten Sprache.
gp SimpleDateFormat( String pattern )
Erzeugt ein SimpleDateFormat-Objekt mit dem vorgegebenen Formatierungs-String in der voreingestellten Sprache.
gp SimpleDateFormat( String pattern, Locale locale )
Erzeugt ein SimpleDateFormat-Objekt mit dem vorgegebenen Formatierungs-String in der Sprache locale.
gp SimpleDateFormat( String pattern, DateFormatSymbols formatSymbols )
Erzeugt ein SimpleDateFormat-Objekt mit dem vorgegebenen Formatierungs-String und einem Objekt formatSymbols, welches die formatierungstypischen Informationen sammelt.
gp void applyPattern( String pattern )
Setze den Formatierungs-String.

Beispiel Wir setzen einen eigenen Formatierungs-String:
DateFormat fmt = new SimpleDateFormat( "EE', den' dd.MM.yy 'um' hh:mm:ss" );

Setzen wir dies zu einem Beispiel für unseren Sprachraum zusammen:

Listing 10.12 ComplexDateFormater.java

import java.util.*;
import java.text.*;
public class ComplexDateFormater
{
  public static void main( String args[] )
  {
    SimpleDateFormat fmt = new SimpleDateFormat();
    fmt.applyPattern( "EEEE', 'dd. MMMM yyyy 'um' hh:mm:ss" );
    Calendar cal = new GregorianCalendar();
    System.out.println(fmt.format(cal.getTime())); // Montag, 02. Mai 2003 um 11:46:31
  }
}

Einige Formatierungs-Strings für den deutschen Raum:


Formatierungs-String Ergebnis

Yyyy.MM.dd G 'at' hh:mm:ss z

2001.03.12 n. Chr. at 03:36:44 GMT+01:00

EEE, MMM d, ''yy

Mo, Mrz 12, '01

h:mm a

3:37 PM

hh 'o''clock' a, zzzz

03 o'clock PM, GMT+01:00

K:mm a, z

3:38 PM, GMT+01:00

yyyyy. MMMMM. dd GGG hh:mm aaa

2001. März. 12 n. Chr. 03:38 PM

Tabelle 10.5 Symbole im Formatierungs-String zur Steuerung der Ausgabe

Der voreingestellte Formatierungs-String der Sprachen

Mit der Methode toPattern() von SimpleDateFormat können wir uns den Formatierungs-String, nach dem das Datum und die Zeit formatiert werden, ausgeben lassen:

SimpleDateFormat formater = (SimpleDateFormat) DateFormat.getDateInstance(
                               DateFormat.LONG );
System.out.println( formater.format( cal.getTime() ) +
                    " mit dem Pattern " +
                    formater.toPattern() +
                    "\nLocalized: " +
                    formater.toLocalizedPattern() );

Die Methode toLocalizedPattern() gibt einen Formatierungs-String in der aktuellen Sprache zurück.


Beispiel Für unser oben erzeugtes Standarddatum ergeben sich für das Pattern und das übersetzte Pattern folgende Ausgaben:
30. September 1997 mit dem Pattern d. MMMM yyyy
Localized: t. MMMM uuuu

Wir sehen: Der übersetzte String ist als neuer Formatierungs-String ungültig, denn weder »t« noch »u« sind erlaubte Formatierungszeichen. Allerdings können wir mit der Methode applyLocalizedPattern(String) diesen Formatierungs-String nutzen, denn es gibt zusätzlich auch eine lokalisierte Version der Formatiersymbole. Also können wir auch für Deutschland einen Formatierungs-String mit Symbolen anwenden, der von der übersprachlichen Version abweicht. Folgendes ist denkbar:

format.applyLocalizedPattern( "t. MMMM uu" );

Er sollte in der Praxis nicht benutzt werden.

Verschreiben wir uns aus Versehen im Formatierungs-String und ein Zeichen taucht nicht unter den erlaubten Zeichen auf, dann ist uns eine Laufzeit-Exception sicher. So führt ein falsch gesetztes »Y« (fälschlich für Year) zu der Meldung:

java.lang.IllegalArgumentException:Illegal pattern character'Y'

class java.text.SimpleDateFormat
extends DateFormat

gp void applyLocalizedPattern( String pattern )
Setzt den Formatierungs-String. Eine Besonderheit ist die Anpassung der Formatierungssymbole, also zum Beispiel uuuu statt yyyy für Jahr.
gp String toPattern()
Liefert den Formatierungs-String.
gp String toLocalizedPattern()
Liefert den übersetzten Formatierungs-String. Substituiert einige Formatierungssymbole.

Galileo Computing

10.8.2 Parsen von Datumswertendowntop

Mit der Klasse DateFormat können wir auch Strings zerlegen, die ein Datum darstellen. Dazu bietet die Klasse zwei Varianten von parse() an, die ein Datum-Objekt zurückliefern. So entspricht der Zeit-String »07/10/96 4:5 PM, PDT« einem Datum, das Date(837039928046) gleichkommt.


Beispiel Parse ein Datum, welches das Format »Jahr-Monat-Tag« hat, mithilfe der Klasse SimpleDateFormat.

SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd" );
Date date = format.parse( "2002-03-12" );

Leider ist der Funktionsaufruf von parse("Das Datum") mit dem DateFormater, der als Ergebnis von getDateInstance(Locale.GERMANY) zurückgegeben wird, nicht richtig - obwohl die HTML-Dokumentation dies suggeriert. Es gibt nämlich keine getDateInstance()-Methode, die nur ein Locale nimmt. Somit müssen wir eine nicht lokale Variante wählen, zum Beispiel durch die parameterlose Funktion getDateInstance(). Dann können wir von dem DateFormater die Methode parse(String) aufrufen. Diese muss aber in einen try- und catch-Block gesetzt werden.


Beispiel Fehlerfall bei parse() abfangen:
DateFormat formater = DateFormat.getDateTimeInstance();
try
{
  Date date = formater.parse( "1.10.1997 11:54:56" );
} catch ( ParseException e ) { ... }

Jetzt haben wir ein Datum in ein Date-Objekt umgewandelt. Es taucht aber wieder das Problem auf, dass Date nicht auf ein spezielles Land und auf eine Zeitzone angepasst ist, sondern die GMT in Englisch repräsentiert. Wandeln wir das Datum mit der toString() in ein String-Objekt um, so erhalten wir den fehlerhaften String »Wed Oct 01 09:54:56 GMT+00:00 1997«.

Um nun wieder eine lokalisierte Version zu schaffen, bemühen wir wieder das Objekt formater, das nach den gleichen Regeln der Umwandlung von String nach Datum aus dem Datum wieder einen String erzeugt.

formater2 = DateFormat.getDateTimeInstance( DateFormat.LONG, DateFormat.LONG );
System.out.println( formater2.format( date ) );

abstract class java.text.DateFormat
extends Format
implements Cloneable, Serializable

gp Date parse( String source ) throws ParseException
Zerlegt einen Datum- oder einen Zeit-String.
gp abstract Date parse( String source, ParsePosition pos ) throws ParseException
Zerlegt einen Datum- oder einen Zeit-String und beginnt beim Parsen ab einer vorgegebenen Position.

Parser-Beispiel mit Calendar-Objekt

Im nachfolgenden Beispiel wird die Zeit einem Calendar-Objekt zugewiesen. Mit einem zweiten formater holen wir dann wieder mit getTime() ein auf 1970 oder später beschränktes Datum-Objekt heraus und formatieren dies:

Listing 10.13 DateParser.java

import java.util.*;
import java.text.*;
public class DateParser
{
  public static void main( String args[] )
  {
    DateFormat formater = DateFormat.getDateTimeInstance( );
    try
    {
      Date date = formater.parse( "23.7.2002 12:54:56" );
      Calendar cal = new GregorianCalendar( TimeZone.getTimeZone("ECT") );
      cal.setTime( date );
      DateFormat formater2 = DateFormat.getDateTimeInstance(
                 DateFormat.LONG, DateFormat.LONG );
      System.out.println( formater2.format( cal.getTime() ) );
    } catch ( ParseException e ) { System.err.println( e ); }
  }
}

Die Funktion parse() ist sehr empfindlich, wenn einige Felder nicht angegeben werden. Nach der Dokumentation sollte zwar ein Fehlen der Stunden nichts ausmachen, aber leider ist dann doch immer eine ParseException sicher, ja auch dann, wenn nur die Sekunden fehlen. Trotz dieser Unzulänglichkeiten ist die Klasse SimpleDateFormat sehr komplex und nicht leicht zu durchschauen.


Galileo Computing

10.8.3 Parsen und Formatieren ab bestimmten Positionentoptop

Von den Methoden format() und parse() gibt es zwei Varianten, mit denen Teile eines Strings ausgegeben oder formatiert werden können. Zur Kapselung der Position dient ein neues Objekt ParsePosition. Dieses ist eine Klasse, die von format genutzt wird, um beim Parse-Prozess die aktuelle Position zu verwalten.

Abbildung
Hier klicken, um das Bild zu Vergrößern

Die Klasse kapselt die Position so musterhaft, dass der Quellcode der Klasse hier einmal in Auszügen dargestellt wird:

public class ParsePosition {
  int index = 0;
  public int getIndex() {
    return index;
  }
  public void setIndex(int index) {
    this.index = index;
  }
  public ParsePosition(int index) {
    this.index = index;
  }
}

Obwohl wir eine private Variable index erwarten, kann auf diese dennoch durch die Klassen im eigenen Paket direkt zugegriffen werden. Ein Hoch auf die Datenkapselung und auf die objektorientierte Programmierung.






1 Im November 1999 wurde ein Algorithmus zur Lösung des Jahr-2000-Problems patentiert, der einfach aussagt, dass zweistellige Jahreszahlen unter 30 zu 20XX und alle Jahreszahlen >30 zu 19XX zu ergänzen sind. Das Patent konnte allerdings erfolgreich angefochten werden.





Copyright (c) Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de