vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
Zippen wie die Profis!  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   RSS-Feeds  | Newsletter  | Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2019
 
zurück
Rubrik: Variablen/Strings · Sonstiges   |   VB-Versionen: VB5, VB601.08.05
Der Datentyp DATE - mit Vorsicht zu genießen!

Wer den Date-Datentyp und die Datum-/Uhrzeit-Funktionen verwendet, sollte diesen Tipp unbedingt lesen. Er informiert über Genauigkeiten, Sonderfälle, den Kalender und weitere wichtige Details.

Autor:   Manfred BohnBewertung:     [ Jetzt bewerten ]Views:  43.156 
ohne HomepageSystem:  Win9x, WinNT, Win2k, WinXP, Vista, Win7, Win8, Win10kein Beispielprojekt 

Für die Bearbeitung von Daten, die ein Datum und/oder eine Uhrzeit repräsentieren, stellt Visual Basic den Datentyp 'DATE' zur Verfügung, für den es eine Reihe von Funktionen gibt, die den Rückgriff auf den Kalender und auf relevante Gebietsschema-Einstellungen des Betriebssystems (z.B. Formate) ermöglichen.

Wer diesen Datentyp und die Datum-/Uhrzeit-Funktionen verwendet, sollte den folgenden Text lesen. Er informiert über Genauigkeiten, Sonderfälle, den Kalender und weitere wichtige Details.
(Den VB-Datentyp 'DATE' und die zugehörige Umwandlungsfunktion 'VBA.CDate' darf man nicht mit der Funktion 'VBA.Date' [bzw. 'VBA.Date$'] verwechseln. Diese Funktion setzt das Systemdatum bzw. fragt es ab.)

A.) Die Skala des Datentyps 'DATE'
Intern werden Variablen des Typs 'DATE' als Gleitkommazahlen im IEEE-Format gespeichert. Die Vorkommastellen repräsentieren die Tagesdifferenz zum Skalen-Nullpunkt, die Nachkommastellen die Uhrzeit als den relativen Teil eines Tages. Der Skalen-Nullpunkt ist als 30.12.1899 festgelegt. Und in diesem Zusammenhang ergibt sich bereits das erste kleine Ärgernis: Das Null-Datum '30.12.1899' wird von der Umwandlungsfunktion 'VBA.CDate' einfach verschluckt - zurück erhält man für dieses spezielle Datum nur die Uhrzeit-Angabe.

Allgemein gilt für DATE-Variable:

  • Ganzzahlen im Bereich x <= -1 und x >= +1 werden als Datum interpretiert ( = relative Zahl der Tage zum Nulldatum)
  • Gleitkomazahlen im Bereich x <= -1.0... und x >= 1.0... werden als Datum und Uhrzeit interpretiert
  • alle Zahlenwerte im Bereich -1 < x < +1 werden als Uhrzeit interpretiert.

B.) Die Auswirkungen des IEEE-Formats
Wer sich mit dem IEEE-Format beschäftigt hat (vgl. z.B. Workshop: 'Der Gebrauch des Datentyps DECIMAL') kennt die damit verbundenen Probleme:

1. Es gibt keine eindeutige Entsprechung zwischen dem binären Muster und dem Zeitpunkt (Datum und/oder Uhrzeit), für den der aktuelle Wert einer DATE-Variable steht. Der Vergleich des Inhalts von zwei DATE-Variablen auf Identität sollte deshalb stets (z.B. sekundengenau) über die Funktion 'VBA.DateDiff' erfolgen.

Abfrage auf Gleichheit der DATE-Variablen 'd1' und 'd2':

If VBA.DateDiff("s", d1, d2) = 0 Then ....

Die Skalen-Angabe im Argument 'Interval' bestimmt dabei die geforderte Genauigkeit der Gleichheitsabfrage.

2. 'DATE' gilt als ein 'integrierter numerischer Datentyp'.
Auf DATE-Variablen können deshalb alle Rechenoperationen und Funktionen angewendet werden, die auch der Datentyp DOUBLE zuläßt - es ist lediglich der eingeschränkte Geltungsbereich ( -657434 bis 2958465,x) zu beachten. Bei Berechnungen werden DATE-Variable wie DOUBLE-Variable behandelt. (Man kann deshalb z.B. den Logarithmus eines Datums berechnen, wenn es nach dem Null-Datum liegt). Es ist dennoch - z.B. wegen der IEEE-Problematik - häufig nicht zweckmäßig direkt mit DATE-Variablen zu rechnen, die (auch) Uhrzeiten enthalten (also keine Ganzzahlen sind). Will man z.B. den mittleren Zeitpunkt einer Reihe von Zeitangaben bestimmen, ist es wg. des beschränkten Geltungsbereichs nicht sinnvoll, die Zeiten innerhalb einer DATE-Variable zu summieren ('Überlauf'). Man muss statt dessen eine VARIANT-Variable verwenden und die Date-Variablen bei der Summation durch die Funktion 'VBA.Conversion.CDec' in Decimal wandeln. Nach Abschluss der Summation und der Durchführung der Division kann das Mitttelungs-Ergebnis in der Variant-Variable durch 'VBA.Conversion.CDate' in den mittleren Zeitpunkt (Datum und Uhrzeit) zurücktransformiert werden. Alternativ kann man einen Bezugszeitpunkt wählen und durch 'VBA.DateDiff' die Sekundendifferenzen aller Zeitpunkte zu diesem Zeitpunkt bestimmen und mitteln. Diese mittlere (gerundete) Sekunden-Abweichung ist dann per 'VBA.DateAdd' dem Bezugszeitpunkt hinzuzufügen.

3. Für Berechnungen, bei denen bedeutsame Ausprägungen im Bereich von Sekundenbruchteilen liegen, ist der Datentyp 'DATE' aufgrund seiner beschränkten Darstellungsgenauigkeit prinzipiell nicht geeignet. Für die Speicherung der Uhrzeit als relativer Teil des Tages stehen zwischen 8 und 15 Stellen zur Verfügung, abhängig vom Datums-Wert - man kann deshalb keine allgemeine Angabe zur Darstellungs-Genauigkeit der Uhrzeit machen. Beim Datum '1.1.1900' ( = Tag 2) stehen 14 Nachkommastellen zur Verfügung, ab dem '18.5.1927' ( = Tag 10000) sind es nur noch 10 Stellen (und das gilt bis ins Jahr 2173). Im relevanten Kalenderabschnitt stehen 10 Nachkommastellen zur Speicherung der Uhrzeit als den relativen Teil eines Tages zur Verfügung. Die begrenzte Genauigkeit des Datentyps DATE bei Zeitberechnungen wird auch deutlich, wenn man sich klarmacht, dass die dezimale Darstellung einer Sekunde als relativer Tagesanteil ( = 1 / 86400 ) einen Bruch mit Periode ergibt: 0,00001157407407407....... Das gilt auch für die dezimale Darstellung einer Minute als Tagesanteil ( = 1 / 1440 ): 0,00069444444444........ Und ebenfalls für die Stunde (1/24): 0,04166666666666.......

4. Bei jeder Zuweisung eines Wertes auf eine DATE-Variable kann es zu einem Rundungsfehler bei der Zuordnung zu einem binären Muster kommen. Diese Fehler können bei sich wiederholenden Berechnungen (z.B. in Schleifen zur Verarbeitung von Listen) allmählich anwachsen. Da die Zuweisungsfehler aus der IEEE-Formatierung stammen, lassen sie sich systematisch angeben. Die folgenden Genauigkeits-Angaben beziehen sich auf DATE-Ausprägungen, bei denen zehn Nachkomma-Stellen für die Uhrzeit verwendbar sind: Die Zuweisungsfehler sind jeweils dezimal darstellbar als Dreiergruppe von Zahlen, die sich ab der 11. Nachkommastelle endlos wiederholt. Im Fehlervektor ist die 11.-13. Nachkommastelle der möglichen Fehler angegeben. Die Abweichungen treten jeweils in beide Richtungen (+/-) auf.

Fehlervektor = 000   037   074   111   148   185   222   259   296   333   370   407   444   481

Nur Zeitpunkte, deren Ausprägung in der dezimalen Sekunden-Darstellung restlos durch 27 teilbar ist, lassen sich abweichungsfrei auf eine DATE-Variable zuweisen (das kann evt. systemspezifisch unterschiedlich sein). Zeitpunkte, deren Ausprägung +/-2 Sekunden restlos durch 27 teilbar ist, sind mit dem maximalen positiven bzw. negativen Zuweisungsfehler behaftet. Die einzelnen Fehler-Ausprägungen treten über die Zeitskala mit gleicher Häufigkeit auf. Der mittlere absolute Zuweisungsfehler beträgt deshalb ca. 2.5*10^(-11), der größte Fehler etwa das Doppelte. Da die einzelne Sekunde ca. als 1,16*10^(-5) dargestellt wird, ist der Einzelfehler zwar relativ gering ausgeprägt, bei Berechnungen im Bereich von Millisekunden können aber Fehler im Ergebnis auftreten.

5. Bei umfangreichen Berechnungen unter Einbezug von Tageszeiten ist es deshalb sinnvoll, die Zeitangaben zunächst in Sekundenwerte umzuwandeln und sie auf eine Variable des Typs CURRENCY zuzuweisen. Mit CURRENCY-Variablen kann dann direkt - auch im Millisekunden-Bereich - gerechnet werden, weil Dezimal-Darstellung und Binär-Speicherung eine eindeutige Entsprechung aufweisen und deshalb keine Zuweisungs- und Rundungsfehler auftreten. CURRENCY-Variablen werden intern als Ganzzahlen behandelt, in der Dezimal-Darstellung aber durch 10000 dividiert (es ergeben sich 4 Nachkommastellen). Der Datentyp CURRENCY bietet auch bei sekundengenauer Darstellung im Vorkommabereich eine angemessene Spannweite für Datums- und Zeitwerte, die im Gültigkeitsbereich des Datentyps 'DATE' liegen. Es handelt sich dabei ebenfalls um einen sogenannten 'integrierten VB-Datentyp', der effizient verarbeitet wird. Die Sekundenbruchteile werden ggf. in den Nachkommastellen gespeichert. Setzt man den Zeitpunkt '1.1.100 00:00:00' als Sekunde Null, ergibt sich z.B. für den '1.9.2005 12:00:00' als fortlaufende Sekunde im Datentyp CURRENCY der Wert: 60137035200,0000 Sekunden. In Variablen des Typs CURRENCY können ca. 10000 Zeitpunkte, die auf diese Weise als fortlaufende Sekunde skaliert sind, summiert werden.

C.) Das Verhalten der Zeit-Funktionen für den Datentyp 'DATE'
Die Zeitfunktionen zur Verwendung mit dem Datentyp 'DATE' sind in 'VBA.DateTime' enthalten, aber global deklariert und können deshalb im Code ohne diesen Vorsatz aufgerufen werden, z.B: 'VBA.DateDiff' oder direkt 'DateDiff'.

Die Anwendung der auf den Datentyp DATE zugeschnittenen Zeitfunktionen erfordert eine gewisse Vorsicht.

1. Die Funktion 'VBA.DateDiff' berechnet die (positive oder negative) Differenz zwischen zwei Zeitpunkten und skaliert sie anhand des Arguments 'Interval'. In der VB-Dokumentation ist nicht angegeben, dass 'VBA.DateDiff' automatisch eine Variant-Variable des Untertyps 'Double' zurückgibt, wenn der Geltungsbereich des Datentyps 'Long' nicht ausreicht, um die Ausprägung der Zeit-Differenz darzustellen (also ab ca. 65 Jahren, die in Sekunden dargestellt werden). Man sollte den Rückgabe-Wert dieser Funktion deshalb nicht ungeprüft auf eine LONG-Variable zuweisen. Wird der 31. Dezember mit dem 1. Januar des unmittelbar folgenden Jahres verglichen, gibt die Funktion 'VBA.DateDiff' für das Jahres-Intervall ("yyyy") den Wert 1 zurück, obwohl nur ein Tag vergangen ist (VB-Dokumentation).

Bei der Belegung des Parameters 'Interval' ist Vorsicht geboten. Die intuitive Verwendung der Abkürzungen geht schief: 'y' steht für den Tag im Jahr, für das Jahr statt dessen 'yyyy'. Für Minute steht 'n', weil 'm' bereits für den Monat benutzt wird und 'w' steht nicht für Woche ('ww') sondern für den Wochentag. Zwischen Groß- und Kleinschreibung im Argument wird offenbar nicht unterschieden. Leere oder undefinierte Angaben lösen den Fehler 5 aus (ungültiges Argument).

Gelegentlich liest man auf VB-Seiten im Internet, dass die Funktion 'VBA.DateDiff' Uhrzeit-Differenzen nur berechnen kann, wenn auch ein Datum enthalten ist. Für VB6 kann diese Einschränkung nicht bestätigt werden. Das liegt schon daran, dass (siehe oben) zwischen einer reinen Uhrzeit-Angabe und dem Datum 30.12.1899 bei Date-Variablen intern nicht unterschieden wird. Man darf nur nicht den Fehler machen, die Rückgabe von 'VBA.DateDiff' auf eine DATE-Variable zuzuweisen. Die Datentypen VARIANT oder DOUBLE sind für Funktionsrückgaben zweckmäßig.

2. Die Funktion 'VBA.DateAdd' wendet intern bei der Übergabe nicht-ganzzahliger Werte im Argument 'Number' anscheinend die Fix-Funktion zur Erstellung einer Ganzzahl an, d.h. (falls Interval = "d") beim Wert +1.6 in 'Number' wird 1 Tag addiert, beim Wert -1.6 in 'Number' 1 Tag vom Datum abgezogen. Die Uhrzeit bleibt dabei unverändert. Das gleiche Verhalten gilt für Zeitangaben. (Abweichende Angaben in der VB-Dokumentation sind falsch: Wenn 'Number' kein Wert vom Typ 'Long' ist, wird er vor der Auswertung NICHT auf die nächste ganze Zahl gerundet.) Wenn man eine Rundung durchführen möchte, muss man den Wert für das Argument 'Number' zunächst explizit mit der Funktion 'VBA.Math.Round' auf 0 Nachkommastellen runden. Möchte man exakt 1.6 Tage zu einem Zeitpunkt addieren, muss man mit 86400 multiplizieren und das Resultat als Sekundenwert (Interval = "s") im Argument an 'VBA.DateDiff' übergeben.

3. Die Funktion 'VBA.TimeValue' gibt aus einem String, der als Uhrzeit oder als Datum plus Uhrzeit interpretierbar ist, die Uhrzeit als 'DATE' zurück. Zu diesem Zweck muss mindestens '0:0' im String enthalten sein, also Angaben zu Stunde und Minute. Diese Funktion akzeptiert 'AM' und 'PM' für die Kennzeichnung von Uhrzeiten vor bzw. nach 12 Uhr mittags. Kombiniert man diese Kennungen allerdings mit Uhrzeiten, deren Stundenangabe größer als 12 ist (z.B. 14:00) - die also im AM/PM-Schema nicht vorkommen dürfen -, werden sie ignoriert und lösen keinen Fehler aus: "14:0AM" ---> 14:00:00 (unter der Voraussetzung, dass unter Windows Systemeinstellungen/Ländereinstellungen/Uhrzeit das Zeitformat als HH:mm:ss = 24 Stunden-Anzeige festgelegt ist). Ist in der Ländereinstellung/Uhrzeit die 12-Stunden-Anzeige gewählt ("hh:mm:ss"), müssen dort auch unterscheidbare Symbole für Zeiten vor und nach 12 Uhr definiert werden, sonst sind die 12-Stunden-Zeitangaben in den VB-Funktionen nicht eindeutig. Sind AM/PM als Kennungen definiert, liefert 'VBA.TimeValue' für die eigentlich sinnlose Angabe "23:58:59AM" den Wert '11:58:59 PM' als 'DATE' zurück. Um für diese Funktion unkorrekte Argumente zu erkennen, muss das jeweils eingestellte Windows-Zeitformat abgefragt und dann zusätzlich berücksichtigt werden, ob fehlerhafte Angaben im String-Argument stehen.

Die Funktion 'VBA.DateDiff' interpretiert bei Windows-Einstellung einer 12-Stunden-Anzeige mit den Kennungen AM/PM die fehlende Kennung in einem Zeitstring automatisch als 'Vormittag' und löst keinen Fehler aus. Die Kennung 'PM' in einem Zeitstring wird immer als Zeitangabe nach Mittag interpretiert - unabhängig von der Uhrzeit-Einstellung unter Windows. Es gibt offensichtlich bei den VB-Zeitfunktionen ein internes Nebeneinander von VB-Standardeinstellungen und Windows-Systemeinstellungen. Das kann im Einzelfall zu unerwarteten Ergebnissen führen. Definiert man z.B. unter Windows das Zeitformat 'hh:mm:ss' (12 Stunden-Anzeige) kombiniert mit V und N (vor 12, nach 12) akzeptieren die VB-Zeitfunktionen weiterhin als Eingabe AM und PM in Zeitstrings, liefern aber V bzw. N in 'DATE'-Zeitangaben zurück.

4. Die Funktion 'VBA.TimeSerial' bietet eine zusätzliche Spielerei. Man kann nicht nur aus Stunden-Minuten-Sekunden-Argumenten einen DATE-Wert bilden, der eine Uhrzeit repräsentiert, sondern zugleich auch Zeitwerte addieren und subtrahieren. Die VB-Dokumentation meldet, man könne auf die Argumente Werte im Geltungsbereich Integer zuweisen - kann man auch! Das zweite Argument 'Minute' akzeptiert einen 'beliebigen numerischen Ausdruck'. VBA.TimeSerial(12,-15, 0) liefert einen Zeitwert der - völlig korrekt - 15 Minuten vor 12 Uhr liegt: 11:45:00
VBA.TimeSerial(12, -24*60, 0) liefert einen Zeitwert der - ebenfalls völlig korrekt - 24 Stunden vor 12 Uhr liegt: 12:00:00

VBA.TimeSerial(12, -48*60, 0) liefert eine Uhrzeit, die 48 Stunden vor 12 Uhr liegt? Schön wär's! Was kommt ist: '29.12.1899 12:00:00'. Die Funktion zaubert plötzlich ein Datum aus dem Ärmel! Die Tageswechsel sind bei der Addition und Subtraktion von Zeitintervallen intern NICHT abgefangen worden, obwohl es sich explizit um eine Uhrzeit-Funktion handelt, die Integer-Werte als Argumente akzeptiert. (Das dargestellte Datums-Problem tritt natürlich auch bei der Addition von Zeit-Intervallen auf). Korrekte Uhrzeit-Ergebnisse erhält man nur durch das explizite Auslesen der Uhrzeit: VBA.TimeValue(VBA.TimeSerial(12, - 96*60,0)) liefert: 12:00:00 (intern: 0,5) Ist man tatsächlich an den Zeitintervallen interessiert, muss man die Date-Rückgabe der Funktion 'VBA.TimeSerial' in einen Double-Wert umwandeln: ZI = VBA.Conversion.CDbl(VBA.TimeSerial(12, - 96*60,0)) liefert in der Double-Variable ZI den Wert -3.5. Eine reine Uhrzeit liefert 'VBA.TimeSerial' nur für die interne Darstellung zwischen -1 < x < 1 ( = Null-Tag). Bei der Übergabe nicht-ganzzahliger Werte in Funktionsargumenten findet intern eine automatische Ganzzahl-Rundung entsprechend der ROUND-Funktion (bzw. der CINT-Zuweisung) statt. Wenn man 1,5 Minuten von 12 Uhr abziehen möchte, müssen die Argumente VBA.TimeSerial(12,-1,-30) übergeben werden.

5. Die Funktion 'VBA.DateSerial' arbeitet wie die Funktion 'VBA.TimeSerial', aber für Datumsangaben. Die Funktion reagiert auf die Windows-Ländereinstellung/Datum. Dort kann explizit festgelegt werden, wie zweistellige Jahresangaben zu interpretieren sind. Um mit dieser Funktion keine unerwarteten Probleme zu bekommen, sollte man deshalb stets vierstellige Jahresangaben im Argument 'Year' verwenden. Es ist schema-spezifisch, bei welchem Jahr die Interpretation eines zwei-stelligen 'Year'-Arguments von 19.. in 20.. wechselt. (Abweichende Angaben in der VB-Dokumentation, die besagen, dass zweistellige Jahresangaben prinzipiell als im Bereich 1900 bis 1999 liegend interpretiert werden, beziehen sich vermutlich auf ältere VB- oder Windows-Versionen.)

6. Auch die Umwandlungsfunktion 'VBA.CDate' weist gewisse 'Eigenarten' auf: VBA.CDate("30.2.1999") löst den Fehler 13 (Typen unverträglich) aus. Das ist korrekt, weil es dieses Datum nicht gibt. VB.CDate("29.2.1999") liefert als Ergebnis keine Fehlermeldung, sondern: 27.2.9900. (Man beachte die einstellige Angabe des Monats!) Die Funktion zieht die Ziffern im String einfach zu der Ganzzahl 2921999 zusammen, interpretiert diesen Wert als fortlaufende Tageszahl und rechnet ihn in ein Datum um. Das macht die Funktion anscheinend mit allen 29.2 in Nicht-Schaltjahren - andere Datums-Angaben werden korrekt verarbeitet. Gibt man das fehlerhafte Datum als 29.02.1999 ein, wird - wie erwartet - der Fehler 13 ausgelöst. Man sollte der Funktion 'VBA.CDate' deshalb nur explizit formatierte Strings als Argument übergeben. Eine einfache Jahreszahl wird von 'VBA.CDate' ebenfalls als fortlaufende Tageszahl interpretiert, während eine Monats- und Jahresangabe als Datum behandelt wird: VBA.CDate("8.2000") wird als '01.08.2000' zurückgegeben. Bei der Eingabe von Datums- oder Zeitangaben im Quellcode empfiehlt die VB-Dokumentation die Verwendung von sog. Literalen (vgl. dort).

7. Die VB-Funktion 'VBA.Strings.Format' kann durch 'benannte Formate' ( = Strings: "General Date", "Long Date", "Medium Date", "Short Date", "Long Time", "Medium Time", "Short Time"), die zur Laufzeit eines Programms jeweils gültigen Ländereinstellungen verwenden und dabei die Spracheinstellungen des Benutzers bei Ausgaben von Monats- oder Tagesnamen einbeziehen. Die genaue Bedeutung dieser Format-Kennungen kann im Kapitel "Formatieren von Zahlen, Datums- und Uhrzeitangaben" der VB-Dokumentation nachgelesen werden.

Da diese Formatbezeichnungen nicht als Konstanten im Objektkatalog auftauchen, empfiehlt es sich, sie als öffentliche String-Konstanten in einem Standardmodul zu deklarieren. Das ist notwendig, weil Tippfehler in diesen Format-Strings vom Compiler nicht erkannt werden können und im Ergebnis völlig unsinnige Ausgaben erzeugen. Das fehlerhafte Format wird als String ausgegeben und dabei werden bestimmte Buchstaben - bei einem DATE-Argument in 'Expression' - automatisch als Zeitformat verwendet.

' ========================================================
Const cGeneral_Date As String = "General Date"
Const cLong_Date As String = "Long Date"
Const cMedium_Date As String = "Medium Date"
Const cShort_Date As String = "Short Date"
 
Const cLong_Time As String = "Long Time"
Const cMedium_Time As String = "Medium Time"
Const cShort_Time As String = "Short Time"
' =========================================================

Mit Ausnahme von "General Date" liefern die benannten Formate entweder Datum oder Uhrzeit. Die benannten Formate können nicht in einem String kombiniert werden. Sie werden in diesem Fall nicht mehr erkannt. Um sowohl das Datum als auch die Uhrzeit in der 'Long'-Variante auszugeben, sind deshalb 2 Aufrufe der Format-Funktion notwendig: Format(dt, cLong_Date) + " " + Format(dt, cLong_Time).

Es ist zu beachten, dass die Funktion 'VBA.Strings.Format', nicht zur 'DateTime'-Gruppe gehört. Sie akzeptiert im Argument 'Expression' einen beliebigen Ausdruck. Bei Verwendung der benannten Formate wird der Ausdruck - falls numerisch interpretierbar - intern automatisch entsprechend der Funktion 'VBA.Conversion.CDate' in einen DATE-Wert umgewandelt; ggf. wird dabei der Fehler 6 "Überlauf" ausgelöst. Übergibt man allerdings einen - als Datum/Uhrzeit ungeeigneten - String im Argument 'Expression' wird kein Fehler ausgelöst, sondern die Format-Angabe wird ignoriert und der String (unverändert) zurückgegeben. Vor Aufruf der Funktion 'Format' mit den benannten Formaten sollte man deshalb durch 'VBA.Information.IsDate' prüfen, ob der Ausdruck einen geeigneten Wert ergibt. Eine Alternative zur Formatierung stellt die Funktion 'VBA.Strings.FormatDateTime' dar, die sich ebenfalls auf die Ländereinstellungen des Systems bezieht. Für das Argument 'NamedFormat' sind in 'VBA.VbDateTimeFormat' Konstanten deklariert.

8. Die Funktion 'IsDate' reagiert auf Angaben in Strings ebenso tolerant wie andere VB-Zeitfunktionen. Den String "1900" weist sie zwar zurück, aber bereits das unvollständige Datum "12.1900" wird als gültiger DATE-Wert akzeptiert. Das gilt auch für den String "12.22" . CDate("12.22") liefert ==> "22.12.2005" = automatische Verdrehung von Tag und Monat sowie Ergänzung des aktuellen Jahres. (Diese Beispiele sind teilweise von den Windows-Ländereinstellungen abhängig!) Je nach Geschmack und Anwendungs-Kontext kann man diese Eigenarten als 'komfortabel und flexibel' oder auch als 'unberechenbar' einstufen. Letztlich fehlt in 'VBA.DateDiff' eine Konstante, durch die der 'Toleranzgrad' dieser Funktionen wählbar wäre. Häufig kommt man nicht darum herum, die VB-Funktionen durch eigene Funktionen zu kapseln, die zunächst bestimmte Prüfungen der Argumente und geeignete Umwandlungen vornehmen.

D.) 'DATE' und der Kalender
Der Datentyp 'DATE' verarbeitet formal Datumswerte von 1.1.100 bis 31.12.9999. Doch wie sieht es mit dem Geltungsbereich des Kalenders aus, der dabei verwendet wird?

Das Verhalten aller datenbezogenen (Datums-) Funktionen in VBA wird durch die Einstellung der Calendar-Eigenschaft bestimmt. Zu den Funktionen, die von der Einstellung der Eigenschaft 'VBA.DateTime.Calendar' betroffen sind, gehören 'CDate', 'Date', 'DateAdd', 'DateDiff', 'DatePart', 'DateSerial', 'DateValue', 'Day', 'Format', 'Month', 'Weekday' und 'Year' (VB-Dokumentation). Die Standardeinstellung dieser Eigenschaft ist festgelegt durch die Konstante 'VBA.VbCalendar.vbCalGreg' ( = 0).

Der gregorianische Kalender gilt (im Prinzip) seit dem 15.10.1582. Er regelt, dass nach dem 4.10.1582 direkt der 15.10.1582 folgt. Dadurch ist der über Jahrhunderte kummulierte Fehler des Julianischen Kalenders (benannt nach Julius Cäsar), dessen Jahr gegenüber dem Sonnenjahr ca. 11 Minuten zu lang war, auf einen Schlag korrigiert worden. Die Wochentage wurden dabei allerdings nicht umgestellt. Diese Reform (durch Papst Gregor XIII.) ist zunächst nur von 'katholischen' Ländern übernommen worden. Speziell in Deutschland - teils katholisch, teils reformiert - herrschte lange Zeit ein Nebeneinander von 'julianischem' und 'gregorianischem' Datum. Der in VB6 verwendete gregorianische Kalender berücksichtigt diese ursprüngliche Reform nicht - insofern sind seine Angaben für Zeitpunkte vor dem 15.10.1582 nicht korrekt.

  • VBA.Datediff("d", CDate("04.10.1582"), CDate("15.10.1582")) liefert 11 statt 1.
  • VBA.DateAdd("d",1, CDate("04.10.1582")) liefert 05.10.1582 statt 15.10.1582.
  • VBA.DatePart("w", CDate("15.10.1582")) liefert 6 = Freitag (korrekt!)
  • VBA.DatePart("w", CDate("04.10.1582")) liefert 2 = Dienstag (statt Donnerstag)

In England und seinen Kolonien (z.b. die heutigen USA) ist der gregorianische Kalender erst 1752 eingeführt worden. Auf den 2.9.1752 folgte unmittelbar der 14.9.1752. Im integrierten Kalender mancher Varianten des Betriebssystems UNIX ist dieser Tagessprung berücksichtigt. Der VB6-Kalender ignoriert auch diese Anpassung.

  • VBA.Datediff("d",CDate("02.09.1752"),CDate("14.09.1752")) liefert 12 statt 1.
  • VBA.DateAdd("d",1,CDate("02.09.1752")) liefert 03.09.1752 statt 14.09.1752.
  • VBA.DatePart("w",CDate("14.09.1752")) liefert 5 = Donnerstag (korrekt!)
  • VBA.DatePart("w",CDate("02.09.1752")) liefert 7 = Samstag (statt Mittwoch)

Die VB6-Kalenderfunktionen liefern erst ab Einführung des gregorianischen Kalenders in einer Region den korrekten Wochentag zu einem Datum. Eine Liste mit den regionalen historischen Einführungs-Zeiten findet man unter:  www.ghgrb.ch/genealogicalIntroduction/kalender_greg_start_chron.html

Die Schaltjahr-Regelung, die im gregorianischen Kalender gilt, wird vom Windows-Kalender richtig abgebildet: bei Teilbarkeit der Jahreszahl durch 4, aber nicht bei Teilbarkeit durch 100, es sei denn, die Teilbarkeit durch 400 ist gegeben. Auch hier das Problem: Für die Zeit vor 1583 bzw. 1752 galt das noch nicht. Julianischer Kalender: ALLE 4 Jahre wurde ein Schaltjahr begangen.

Die Anwendung des gregorianischen Kalenders auf historische Zeiträume, in denen er noch nicht gegolten hat - wie die VB-Funktionen dies tun -, gibt es eigentlich nur in der Astronomie und nennt sich 'proleptischer Gregorianischer Kalender' (proleptisch = vorwegnehmend).

In der Bundesrepublik ist der Kalender nach DIN 1355 genormt. (Die Jahreslänge, die Schaltjahr-Regelung, die Jahreszählung, die Monats- und Wochentags-Namen, sowie die Wochenzählung sind festgelegt - in Übereinstimmung mit dem Gregorianischen Kalender unter Hinzufügung einiger ergänzender Präzisierungen).

Bereits seit 1978 wird auf Beschluss der UNO der Montag international als der erste Tag der Woche eingestuft. Die entsprechende VB6-Voreinstellung ignoriert das und setzt den Sonntag als Wochenanfang. Das Argument 'FirstDayOfWeek' muss auf 2 = vbMonday gesetzt werden, um den Montag als Wochenanfang auszuwählen. Das betrifft die Funktionen 'VBA.DateDiff', 'VBA.DatePart' und 'VBA.WeekDay' - sowie 'VBA.Strings.Format'.

Fazit:
Hinter dem Datentyp 'DATE' und den entsprechenden Zeitfunktionen von VB steht intern ein relativ einfaches Skalen-Konzept. Es bleibt dem Anwender überlassen, die Brauchbarkeit für seine Zwecke im einzelnen selbst zu testen und dann Funktionen zu entwickeln, die sich in seinem Anwendungs-Kontext erwartungsgemäß verhalten, dabei bestimmte unerwünschte VB-Eigenheiten abfangen und die Windows-Ländereinstellungen für Datum und Uhrzeit explizit abfragen und systematisch verarbeiten.

Für europäische Anwendungen muss entweder der julianische Kalender zusätzlich integriert werden - einschließlich des (national/regional unterschiedlichen) Zeitpunktes seiner Ablösung durch den gregorianischen -, oder der Geltungsbereich von DATE-Variablen muss auf den Zeitraum der Geltung des gregorianischen Kalenders eingeschränkt werden. Die 'proleptische' Anwendung des VB-Kalenders erstellt für die 'julianischen Zeiten' falsche Wochentage und falsche Zeit-Differenzen (wg. der Schaltjahres-Regelung).

Bei US-Anwendungen empfiehlt es sich, zunächst die Nachkommen der Ureinwohner über ihre vor-gregorianischen Kalender zu befragen. Hier ist freilich mit erheblichen regionalen Unterschieden zu rechnen
 

Dieser Tipp wurde bereits 43.156 mal aufgerufen.

Voriger Tipp   |   Zufälliger Tipp   |   Nächster Tipp

Über diesen Tipp im Forum diskutieren
Haben Sie Fragen oder Anregungen zu diesem Tipp, können Sie gerne mit anderen darüber in unserem Forum diskutieren.

Neue Diskussion eröffnen

nach obenzurück


Anzeige

Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6

Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
- nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
- Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
 
   

Druckansicht Druckansicht Copyright ©2000-2019 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel