|
|
-> Offene bzw. zu klärende bzw. festzulegende Punkte ProblemDie Konvertierung von Datum-, Zeit- und Timestamp-Angaben zwischen einer Datenbank, Servern und Clients funktioniert in Java nicht reibungslos. Es werden teilweise unterschiedliche Timezones berücksichtigt, die das Ergebnis dann um eine Stunde verfälschen (beim Datum an 0 Uhr Grenzen sogar um einen Tag). Diesem sollte mit einer einheitlichen Klasse abgeholfen werden. Nebenbei hilft die Umsetzung der internen LösungEine oder mehrere Java-Klassen, die die Generierung, Transformierung, Parsing und
Formatieren eines Zeitstempels übernehmen. Die Klasse AnsatzUm das hauptsächliche Problem der Timezones aus der Welt zu schaffen, wird
eine Basis festgelegt. Wir entschieden uns für die "jetzt gültige lokale
Uhrzeit". Wenn wir 11:15 Uhr haben, dann ist 11:15 Uhr mitteleuropäische
(Sommer-)Zeit gemeint. Umgerechnet auf Greenwich wäre das 10:15 Uhr
(Winterzeit) oder 9:15 Uhr (Sommerzeit). Für den Datenbankzugriff muß dann
natürlich die Timezone des DB-Hosts berücksichtigt werden - sprich: beim
temporären Generieren eines Um korrekte Zeitberechnungen durchzuführen, ist das Umsetzen des Gregorianischen Kalenders mit all seinen Regeln notwendig. Als Startbasis wurde der 1.1.0001 verwendet. Intern werden somit die Anzahl der Tage seit dem 1.1.0001, die Anzahl der Sekunden seit Tagesbeginn und die Anzahl der Mikrosekunden seit Sekundenbeginn mitgeführt. DatumsregelnDer Gregorianische Kalender gilt seit dem 15. Oktober 1582. Direkt davor gibt es eine Lücke von 10 Tagen, d.h. nach dem 04.10.1582 folgte direkt der 15.10.1582 (auf Anordnung des Papstes Gregor XIII, daher der Name). Bis zum 04.10.1582 galt der Julianische Kalender. Ein Jahr 0 hat es nie gegeben (d.h. vor dem 1.1.0001 kommt der 1.1.-0001 bzw. 1.1.0001 v.Chr.). Der Julianische Kalender hat für die Schaltjahre eine einfache Regel: alle 4 Jahre im Februar einen Tag mehr. Mit dem Gregorianischen Kalender wurde eine andere Regelung eingeführt: Der 4-Jahres-Abstand bleibt, aber alle 100 Jahre fällt das Schaltjahr aus und alle 400 Jahre findet es doch statt (jeweils zu jedem vollen Jahrhundert). Im Jahr 1900 gab es somit kein Schaltjahr, jedoch aber im Jahr 2000. Ein ganzer Tag dauert 24 Stunden, umgerechnet 86400 Sekunden (24 Stunden * 60 Minuten * 60 Sekunden). Strenggenommen fehlen trotz der neuen Schalttagsregel jährlich 27 Sekunden, die in einigen Tausend Jahren zu einer signifikanten Größe heranwachsen werden (in 100 Jahren sind dies schon 45 Minuten), aber die Tatsache wird bei heutigen Datums-Implementierungen ignoriert. BerechnungenAnhand der intern gespeicherten Anzahl der Tage seit 1.1.0001 lassen sich leicht Datumsberechnungen durchführen. Bei tageweiser Addition bzw. Subtraktion genügt das Anpassen der Anzahl Tage. Bei monats- und jahresweiser Addition bzw. Subtraktion werden ausgehend vom aktuellen Monat und Jahr blockweise Operationen durchgeführt. An Schaltjahresgrenzen gibt es zusätzliche Flags, die das Verhalten steuern. Möglich sind dann Einstellungen wie Exception werfen, vor die Grenze setzen oder nach die Grenze. KonstruktorenDie einfachsten Konstruktoren sind die, die aus einer Datumsangabe oder einem vollständigen Timestamp ein DateTime anlegen: DateTime(day,month,year); DateTime(day,month,year,hour,minute,second); DateTime(day,month,year,hour,minute,second,micros); Intern werden aus diesen Angaben die seriellen Zahlen für Tage, Sekunden und
Mikrosekunden ermittelt. Damit ist das DateTime-Objekt dann bereit für weitere
Operationen. Vorteilhaft ist hier die direkte Angabe der Monatsnummer 1 bis 12
statt den Monaten 0 bis 11, wie man es von UNIX bzw Als weiteren Konstruktor gibt es DateTime(millis,timezone_diff); In einem Java-System sind die Der Konstruktor ohne Zeitzonenangabe findet sich in der erweiterten Klasse: DateTimeExtended(millis); Intern wird die Zeitzone anhand eines lokalen Der Konstruktor ohne Parameter DateTimeExtended(); verwendet den Konstruktor Als letzten Konstruktor gibt es den Konvertierer: DateTimeExtened(date);
Umwandlung UNIX millis <=> DateTimeDie "seriellen Werte" des DateTime sind im folgenden die drei wesentlichen Komponenten des DateTime: Tage seit 1.1.0001, Sekunden seit MItternacht und Mikrosekunden seit Sekundenbeginn. java.util.Date (und abgeleitete Klassen) nach DateTimeExtrahieren der UNIX Verwendung: Konstruktor UNIX millis nach DateTimeDie Umwandlung ist etwas problematisch: Da nicht bekannt ist, in welcher
Timezone das Die erweiterte Klasse // millis sind die gegebenen Millisekunden long diff = -1000*60*(new Date(millis)).getTimezoneOffset(); // getTimezoneOffset() liefert Minuten, d.h. muß erst in Millisekunden umgewandelt werden // neg. Vorzeichen ist notwendig, damit der Wert relativ zu UTC wird (statt zu lokal) Die Summe aus Verwendung: Konstruktor DateTime nach java.util.Date (und abgeleitete Klassen)Ein vorhandenes Verwendung: statische Methoden DateTime nach UNIX millisEin vorhandenes Verwendung: Methode
Offene bzw. zu klärende bzw. festzulegende PunkteWann beginnen wir mit der Datumsrechnung?Ich habe hier einfach mal den 1.1.0001 als Startpunkt angenommen. Bezüglich HIT ist dies weit hergeholt, aber ich pflege bei sich ständig ändernden Parametern vorausschauend (hier müßte man fast sagen: rückschauend :-) zu programmieren. Die Schaltstelle zwischen julianisch und gregorianisch im Oktober 1582 zu programmieren, hat etwas Aufwand gekostet, wurde aber laut der JUnit Tests erfolgreich bewerkstelligt. Ich hätte allerdings kein Problem damit, wenn wir uns beispielsweise auf den 1.1.1600 als Startpunkt festlegen. Dann kann der ganze julianische Kalender aus der Klasse herausfallen und die Berechnung sogar etwas schneller von statten gehen. Daten vor dem 1.1.1600 wären aber dann nicht möglich. JahreszahlenSoll sich die Klasse selbst um die Korrektur der Jahreszahlen kümmern, oder eher nicht? Derzeit nimmt DateTime ein Jahr 90 als 90 auf und nicht als 1990. Die Regel, wenn das Jahr >= 70 und < 100 ist, daß automatisch 1900 addiert wird, sollte eher eine externe (statische) Methode übernehmen. Umwandlung millis in DateTimeIn einem Java-System sind die Millis die Millisekunden seit dem 1.1.1970
00:00
Uhr UTC.
Auch kein Problem bereiten Umsetzungen von Was ist aber mit den Millisekunden, die in eine DB
sollen? Strenggenommen müßte man für Zeitzonen der Timestamps, die für eine
Datenbank gedacht sind, über eine Dummy-Abfrage und dem erhaltenen Aufteilung Time, Date und Timestamp
Ich würde daher eventuell eiskalt hergehen und die drei Basiselemente
Datum, Zeit und die Mikrosekunden in separate Klassen bzw. Werte auslagern. Ein
Timestamp bestünde dann aus Attributen der Objekte Datum und Zeit und einem Eine Datumsangabe hat dann auch wirklich nur Datumsangaben und keinerlei Zeitkomponenten. Gleiches gilt für die Zeit, die dann ohne Datum auskommt und dann sogar die Möglichkeit hätte, negative Zeitangaben zu besitzen (um das Beispiel vom vorherigen Absatz durchführen zu können). SommerzeitDas Ignorieren der Zeitzonen ist kein Problem. Schwieriger ist es da mit der
Sommerzeit. Strenggenommen gibt es beispielsweise kein 27.3.2005 2:30 Uhr. An
dem Tag wären 2:00 und 3:00 die selbe Uhrzeit. Nach
|