Java Date und Calendar

+ andere TechDocs
+




Inhalt

  1. Datumsarithmetik
  2. Java-Klassen-Hierarchie einiger Date- und Calendar-Klassen
  3. Aufgaben von Date, SimpleDateFormat und GregorianCalendar
  4. Benutzung von Date, SimpleDateFormat und GregorianCalendar
  5. Berechnung von Datums-Differenzen
  6. Konvertierung von und zu LocalDate
  7. Weiterführende Links


Datumsarithmetik

Datumsarithmetik ist keine triviale Aufgabe. Es müssen viele Bedingungen beachtet werden:

Java-Klassen-Hierarchie einiger Date- und Calendar-Klassen



Aufgaben von Date, SimpleDateFormat und GregorianCalendar

Bis JDK 1.0.2 diente die Klasse Date zur Darstellung und Manipulation von Datumswerten.
Ab JDK 1.1 wurde Calendar zur Bearbeitung von Datumswerten eingeführt und fast alle Methoden von Date als Deprecated markiert.
Die wichtigsten Aufgaben der drei wichtigsten Klassen sind:

Benutzung von Date, SimpleDateFormat und GregorianCalendar

TimeZone

Der Wert von TimeZone.getDefault() sollte auf der System Property "user.timezone" basieren, welcher von der JVM gesetzt werden kann.
Aber zumindest in früheren JDK-Versionen war sie häufig nicht gesetzt. Dann benutzt TimeZone.getDefault() einen eigenen 'Fallback'-Wert, der bis JDK 1.1.3 'PST' (North American Pacific Timezone) war und danach auf 'GMT' (Greenwich Mean Time) geändert wurde.
Ab JDK 1.2 benutzen Date, SimpleDateFormat und Calendar diese Default-Zeitzone. Vorher war Calendar in SimpleDateFormat auf die erste lokale Zeitzonen-Ressource gesetzt (z.B. in USA auf 'PST'). Diese Unsicherheit kann leicht vermieden werden mit:
myDateFormat.setTimeZone( TimeZone.getDefault() );

import java.util.*;
// Anzeige aller Zeitzonen-IDs:
String[] ssIDs = TimeZone.getAvailableIDs();
for( int i=0; i<ssIDs.length; i++ )  System.out.println( ssIDs[i] );
// Anzeige der aktuellen Default-Zeitzone:
System.out.println( "Default-Zeitzone = " + TimeZone.getDefault().getID() );       // z.B. 'Europe/Berlin'
System.out.println( "user.timezone = " + System.getProperty( "user.timezone" ) );  // z.B. 'Europe/Berlin'

Date

// Aktuelles Datum:
import java.util.*;
Date dt = new Date();
System.out.println( "Date = " + dt );          // z.B. 'Fri Jan 26 19:03:56 GMT+01:00 2001'
System.out.println( "ms = " + dt.getTime() );  // z.B. '980532236731'

SimpleDateFormat

import java.util.*;
import java.text.*;
Date dt = new Date();
// Festlegung des Formats:
SimpleDateFormat df = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.S" );
df.setTimeZone( TimeZone.getDefault() );                  // nicht mehr unbedingt notwendig seit JDK 1.2
// Formatierung zu String:
System.out.println( "Date = " + df.format( dt ) );        // z.B. '2001-01-26 19:03:56.731'
// Ausgabe für andere Zeitzone:
df.setTimeZone( TimeZone.getTimeZone( "Africa/Casablanca" ) );
System.out.println( "Casablanca = " + df.format( dt ) );  // z.B. '2001-01-26 18:03:56.731'
// Einlesen vom String:
dt = df.parse( "2001-02-03 04:05:06.7" );
System.out.println( "parse = " + df.format( dt ) );       // z.B. '2001-02-03 04:05:06.7'

Calendar und GregorianCalendar

GregorianCalendar benutzt immer das gregorianische Kalendersystem, während Calendar auch andere Kalendersysteme benutzen könnte (z.B. Hebrew oder Islamic). Bislang gibt es von Sun allerdings noch keine anderen Implementationen.
Mit Calendar.getInstance() wird ein Kalender-Objekt im lokal gültigen Kalendersystem erzeugt.
GregorianCalendar() dagegen erzeugt stets ein Objekt im gregorianischen Kalendersystem.
Das Lesen und Setzen von Monatsangaben sollte bevorzugt über die definierten Konstanten erfolgen (z.B. 'Calendar.MARCH'). Wird stattdessen der Integer-Wert benutzt, muss beachtet werden, dass der Januar mit 0 und nicht mit 1 beginnt.
Wenn man mit Calendar.set() ein Feld setzt und anschließend mit Calendar.get() ein anderes Feld liest, waren die Felder vor JDK 1.2 nicht unbedingt konsistent (z.B. konnte der Wochentag falsch sein). In solchen Fällen kann Konsistenz einfach erreicht werden mit:
myCal.setTime( myCal.getTime() );

// Verschiedene Verfahren zur Erzeugung eines Kalender-Objekts:
import java.util.*;
Calendar myCal1 = Calendar.getInstance();                         // lokales Kalendersystem mit aktueller Zeit
Calendar myCal2 = new GregorianCalendar();                        // GregorianCalendar mit aktueller Zeit
Calendar myCal3 = new GregorianCalendar(1956,Calendar.MARCH,17);  // GregorianCalendar mit vorgegebener Zeit

// Setzen von Jahr + Monat + Tag:
myCal2.set( 1956, Calendar.MARCH, 17 );                // ändert so nicht Stunden, Minuten und Sekunden
myCal2.setTime( myCal2.getTime() );                    // nicht mehr unbedingt notwendig seit JDK 1.2
// Zeit setzen mit Date:
myCal2.setTime( new Date() );
// Einzelne Felder extrahieren:
int year = myCal2.get( Calendar.YEAR  );
int mnth = myCal2.get( Calendar.MONTH ) + 1;           // nicht vergessen die 1 zu addieren
int date = myCal2.get( Calendar.DATE  );
System.out.println( date + "." + mnth + "." + year );  // für Formatierung ist SimpleDateFormat besser 

// Calendar ist gut geeignet, um Berechnungen durchzuführen,
// z.B. um den um ein Jahr erhöhten Zeitwert zu berechnen:
myCal2.add( Calendar.YEAR, 1 );

// Umwandlung von Calendar in Date:
Date myDate = myCal2.getTime();
System.out.println( myDate );


Berechnung von Datums-Differenzen

Die Berechnung von Datums-Differenzen ist nicht trivial, wie schon oben unter Datumsarithmetik verdeutlicht wurde.
Das Java JDK bietet dafür bislang keine Methode.
Oft funktioniert die im Folgenden gezeigte vereinfachte Variante. Aber zum Beispiel bei historischen Berechnungen, verschiedenen Zeitzonen oder wenn der eine Zeitpunkt Sommerzeit und der andere Winterzeit hat, kann es zu Fehlern kommen. Dann muss eine Transformation in UTC (Coordinated Universal Time) oder Julian Days vorgeschaltet werden. In der Literatur werden dazu verschiedene und teilweise recht aufwändige Prozeduren vorgestellt.
Die beiden Zeitpunkte werden hier mit Jahr + Monat + Tag definiert, sie könnten aber genauso gut per Date-Objekt definiert werden (s.o.).
Calendar cal_1 = new GregorianCalendar();
Calendar cal_2 = new GregorianCalendar();
cal_1.set( 1997, Calendar.MARCH, 1, 0, 0, 0 );                      // erster Zeitpunkt
cal_2.set( 1998, Calendar.APRIL, 2, 0, 0, 0 );                      // zweiter Zeitpunkt
long time = cal_2.getTime().getTime() - cal_1.getTime().getTime();  // Differenz in ms
long days = Math.round( (double)time / (24. * 60.*60.*1000.) );     // Differenz in Tagen
System.out.println( "Zeit-Differenz in Tagen: " + days );


Konvertierung von und zu LocalDate

Seit Java 8 gibt es ein erheblich verbessertes Time und Date API. Eine der neuen Klassen ist java.time.localDateTime. Die Konvertierung von Date nach localDateTime und umgekehrt kann folgendermaßen erfolgen:
// Date zu LocalDateTime:
LocalDateTime localDateTime = LocalDateTime.ofInstant( Instant.ofEpochMilli( date.getTime() ), ZoneId.systemDefault() );

// LocalDateTime zu Date:
Date date = Date.from( localDateTime.atZone( ZoneId.systemDefault() ).toInstant() );

// LocalDateTime zu LocalDate:
LocalDate localDate = localDateTime.toLocalDate();

// LocalDate zu Date:
Date date = Date.from( localDate.atStartOfDay().atZone( ZoneId.systemDefault() ).toInstant() );


Weiterführende Links





Weitere Themen: andere TechDocs
© 1998-2007 Torsten Horn, Aachen