Tipp 0447
|
Datumseingabe prüfen
|
 |
|
Autor/Einsender: Datum: |
|
Angie/Jürgen Beil 18.04.2005 |
|
Entwicklungsumgebung: |
|
VB 6/VBA 6 |
|
|
Zur Darstellung des Datums gibt es weltweit sehr verschiedene Schreibweisen. Die selbe Angabe kann in
unterschiedlichen Darstellungen für ein unterschiedliches Datum stehen. Eine Datumsangabe in der
Form 03/11/04 kann beispielsweise interpretiert werden als
|
3. November 2004
11. März 2004
4. November 2003
|
Eine eindeutige Datumsangabe kann durch Angabe des Monatsnamens in ausgeschriebener oder abgekürzter
Form, und durch eine vierstellige Jahreszahl erzielt werden, unabhängig davon, an welcher Stelle Tag,
Monat oder Jahr angegeben werden:
|
3. November 2004
November 3, 2004
3. Nov. 2004
Nov. 3, 2004
|
In diesem Zusammenhang sei hier auf die ISO 8601 in der
Wikipedia - die freie Enzyklopädie
hingewiesen.
ISO 8601 ist ein internationaler Standard der ISO, der Datumsformate und Zeitangaben
beschreibt und Empfehlungen für den Gebrauch im internationalen Kontext ausspricht.
|
|
Steuerelemente für die Datumseingabe |
|
In der Praxis bietet sich für die Eingabe eines Datums in VB das DTPicker- oder
Kalender-Steuerelement an. Damit ist gewährleistet, dass es sich beim Rückgabewert um ein
"gültiges" Datum handelt. Eine weitere Prüfung ist also nicht notwendig.
|
Eine andere Möglichkeit wäre die Eingabe in einer TextBox oder auch InputBox, wobei, wie aus
den weiteren Ausführungen deutlich wird, es nicht sinnvoll ist, dem Anwender nur eine TextBox/InputBox
für die Datumseingabe anzubieten. Besser sind drei TextBoxen, in denen Tag, Monat und Jahr getrennt
voneinander eingegeben werden, oder aber auch drei ComboBoxen.
|
|
Rückgabe der IsDate-Funktion |
|
Die IsDate-Funktion gibt einen Wert vom Typ Boolean zurück, der angibt,
ob ein Ausdruck in ein Datum umgewandelt werden kann. In der MSDN wird der Datumsausdruck wie folgt
beschrieben:
|
"Jeder Ausdruck, der als Datum angesehen werden kann, einschließlich Datumsliterale, datumsähnliche
Zahlen, datumsähnliche Zeichenfolgen und Datumsangaben, die von Funktionen zurückgegeben werden.
Ein Datumsausdruck ist auf Zahlen oder Zeichenfolgen in beliebiger Kombination begrenzt, die ein Datum
im Bereich vom 1. Januar 100 - 31. Dezember 9999 darstellen können.
|
Datumsangaben werden als Teil einer reellen Zahl gespeichert. Werte links vom Dezimalzeichen stehen
für das Datum, Werte rechts vom Dezimalzeichen für die Uhrzeit. Negative Zahlen geben Daten vor dem
30. Dezember 1899 an."
|
Weitere Infos zum Thema Datum und Kalender können der MSDN (VB-Hilfe) und den
Links zum Thema entnommen werden.
|
Immer wieder taucht die Frage auf, wie mit VB/VBA ein vom Benutzer eingegebenes Datum auf Gültigkeit
geprüft kann. Als Antwort wird meistens gegeben: "Mit der IsDate-Funktion !".
Wie aus den folgenden Ausführungen deutlich wird, kann die Verwendung der IsDate-Funktion
jedoch zu unerwünschten Ergebnissen führen.
|
Im deutschsprachigem Raum sieht man oft Codeschnipsel, die wie folgt oder ähnlich aussehen:
|
|
|
Dim dtmDate As Date
If IsDate("03.11.2004") Then
dtmDate = CDate("03.11.2004")
End If
|
|
|
Die obige Abfrage mit IsDate gibt nur dann True zurück, wenn
in den Regions- und Sprachoptionen genau dieses Datumsformat definiert ist, wie beispielsweise
im Gebietsschema Deutsch (Deutschland) ohne manuellen Änderungen.
|
Bessere, aber nicht unbedingt "sichere" Rückgaben können erzielt werden, wenn statt dem Punkt
beispielsweise ein Schrägstrich (/) oder Bindestrich (-) verwendet wird. Die Abfrage
|
|
|
Dim dtmDate As Date
If IsDate("1a20-3-12") Then
dtmDate = CDate("1a20-3-12")
End If
|
|
|
gibt auch True zurück, und mit der CDate-Funktion in ein Datum
umgewandelt wäre das der 20.03.2012 01:00:00 (Gebietsschema Deutsch (Deutschland)).
|
Mit der CDate-Funktion kann ein Datumsausdruck in einen Wert vom Typ
Date umgewandelt werden. Die Rückgabe von
|
|
|
MsgBox Format$(CDate("11/03/04"), "dd. mmmm yyyy")
|
|
|
kann jedoch zu unterschiedlichen Ergebnissen führen. Aus folgender Tabelle gehen die verschiedenen
Datumsrückgaben, je nach eingestelltem Gebietsschema, deutlich hervor.
|
Gegenüberstellung Datumsrückgaben mit verschiedenen Gebietsschemata
|
Zum Vergleich wurden hier die Gebietsschemata Deutsch (Deutschland), Englisch
(Großbritannien (UK)) und Englisch (USA) verwendet, ohne im jeweiligen Gebietsschema selbst
Veränderungen vorzunehmen. Als Beispiel-Datumseingabe wurde ein String angenommen
(entspricht beispielsweise eine Eingabe in einer TextBox), der, je nach Gebietsschema,
von der IsDate-Funktion als "gültiger" Datumsausdruck angesehen wurde oder
auch nicht! Für die Rückgabe wurde, wenn dies möglich war, der Datumsausdruck mit der
Typ-Umwandlungsfunktion CDate in ein Datum umgewandelt und mit der
Format-Funktion für eine eindeutige Datumsausgabe im Format
dd. mmmm yyyy ausgegeben.
|
|
|
Datum (Eingabe) |
Deutsch (D) |
Englisch (UK) |
Englisch (USA) |
|
Beabsichtigtes Rückgabe-Datum: 3. November 2004
|
1 |
03.11.2004 |
03. November 2004 |
IsDate = False |
IsDate = False |
2 |
03/11/2004 |
03. November 2004 |
03. November 2004 |
11. March 2004 |
3 |
11/03/2004 |
11. März 2004 |
11. March 2004 |
03. November 2004 |
4 |
11/03/04 |
11. März 2004 |
11. March 2004 |
03. November 2004 |
5 |
04/11/03 |
04. November 2003 |
04. November 2003 |
11. April 2003 |
6 |
2004/11/03 |
03. November 2004 |
03. November 2004 |
03. November 2004 |
7 |
2004-11-03 |
03. November 2004 |
03. November 2004 |
03. November 2004 |
|
Fiktives Datum: 31. Februar 2004
|
8 |
31.02.2004 |
IsDate = False |
IsDate = False |
IsDate = False |
9 |
31.02.04 |
04. Februar 1931 |
IsDate = False |
IsDate = False |
10 |
31/02/2004 |
IsDate = False |
IsDate = False |
IsDate = False |
11 |
31/02/04 |
04. Februar 1931 |
04. February 1931 |
04. February 1931 |
12 |
04/02/31 |
04. Februar 1931 |
04. February 1931 |
02. April 1931 |
13 |
2004/02/31 |
IsDate = False |
IsDate = False |
IsDate = False |
14 |
2004-02-31 |
IsDate = False |
IsDate = False |
IsDate = False |
|
Der Versuch, die Logik der Datumsrückgaben für die Daten mit zweistelliger Jahreszahl
nachzuvollziehen, könnte wie folgt aussehen:
|
Kann ein Ausdruck als Datum interpretiert werden (Rückgabe der IsDate-Funktion
ist True), wird bei der Typ-Umwandlung in ein Datum (CDate) scheinbar
zunächst davon ausgegangen, dass der Datumsausdruck je nach Einstellung im Gebietsschema
z. B. in der Form Tag/Monat/Jahr (D und UK) oder Monat/Tag/Jahr (USA),
übergeben wurde. Handelt es sich nicht um ein "gültiges" Datum, so wird intern zunächst
Tag und Monat vertauscht, und wenn das auch zu keinem vernünftigen Ergebnis führt,
Jahr/Monat/Tag angenommen.
|
|
|
1. |
Die IsDate-Funktion alleine reicht nicht aus, um eine vom Anwender eingegebenes
Datum auf "Gültigkeit" prüfen zu können.
|
2. |
Wie aus obiger Tabelle ersichtlich, gibt es zwei Datumsformate, die, egal welches Gebietsschema
verwendet wurde, das beabsichtige Datum 3. November 2004 zurückgegeben haben und das
fiktive Datum als nicht korrekten Ausdruck.
|
|
2004/11/03 (Jahr/Monat/Tag)
2004-11-03 (Jahr-Monat-Tag) (ISO 8601)
|
|
Ein gültiger (!) Datumsausdruck im Format yyyy-mm-dd (ISO 8601),
der mit der Typ-Umwandlungsfunktion CDate in ein Datum umgewandelt wird, gibt immer
das gleiche Datum zurück, unabhängig vom eingestellten Gebietsschema. Auch ggf. manuell gemachte
Änderungen in den Regions- und Sprachoptionen haben darauf keinen negativen Einfluss.
|
|
Ersatzfunktionen für die IsDate-Funktion |
|
Die beiden folgenden Funktionen bieten einen Lösungsansatz, um die von einem Anwender in TextBoxen
eingegebenen Datumswerte für Jahr, Monat und Tag auf ein "gültiges" Datum hin überprüfen zu können.
Sie werden wie die IsDate-Funktion verwendet (Rückgabe True/False),
jedoch mit dem Unterschied, dass statt einem Datumsausdruck oder Zeichenfolgenausdruck die Jahres-,
Monats- und Tageszahl als Argumente übergeben werden. Zusätzlich kann als optionales Argument das
Datum in einer Variablen vom Datentyp Date zurückgegeben werden.
|
Anmerkung: Eine Variable vom Typ Date hat standardmäßig den Wert 0. Dieser wird aber als
30. Dezember 1899 00:00:00 Uhr interpretiert! Daher sollte das von der Funktion
zurückgegebene Datum (optionales Argument) nur dann weiter verwendet werden, wenn der Rückgabewert
der Funktion True ist.
|
Datumseingabe mit der IsDate-Funktion prüfen
|
Um mit der IsDate-Funktion eine "sichere" Rückgabe zu erhalten, muss bei der
Auswertung der Eingabe zunächst die Jahreszahl geprüft werden, ob diese im Bereich von 100 bis 9999
liegt, damit das Jahr eindeutig bestimmt werden kann, und nicht aus 20/11/03 (Jahr/Monat/Tag)
z. B. der 20. November 2003 wird, statt wie ggf. beabsichtigt, der 3. November 2020.
|
Anschließend wird der Monat auf Gültigkeit geprüft, dieser muss im Bereich von 1 bis 12 liegen.
|
Um Abfragen bzgl. der Anzahl der Tage im Monat, und im Fall Februar, ob es sich um ein Schaltjahr
gehandelt hat, zu umgehen, wird der eingegebene Wert für den Tag nicht gesondert geprüft, da der
Datumsausdruck nach der Überprüfung der Jahreszahl und des Monats und nach dem Zusammensetzen des Datums
nach ISO 8601 mit der IsDate-Funktion auf ein gültiges Datum hin überprüft werden kann.
Gibt es den Tag im angegebenen Monat nicht, so gibt die IsDate-Funktion False zurück.
|
Die folgende Funktion ist in der Ausführung sehr langsam und dient lediglich zur Veranschaulichung,
wie die IsDate-/CDate-Funktionen doch zum Einsatz kommen könnten.
|
|
|
Public Function IsDateValid_1(ByVal varYear As Variant, _
ByVal varMonth As Variant, ByVal varDay As Variant, _
Optional ByRef dtmDate As Date) As Boolean
Dim strDate As String
If IsNumeric(varYear) Then
If (varYear >= 100) And (varYear <= 9999) Then
If IsNumeric(varMonth) Then
If (varMonth >= 1) And (varMonth <= 12) Then
If IsNumeric(varDay) Then
strDate = Format$(varYear, "0000") & "-" & _
Format$(varMonth, "00") & "-" & _
Format$(varDay, "00")
If IsDate(strDate) Then
dtmDate = CDate(strDate)
IsDateValid_1 = True
End If
End If
End If
End If
End If
End If
End Function
|
|
|
Datumseingabe mit der DateSerial-Funktion prüfen
|
Schneller und effektiver lässt sich eine Datumseingabe mit der DateSerial-Funktion prüfen.
Die DateSerial-Funktion gibt einen Wert vom Typ Variant (Date)
zurück, der die angegebene Jahres-, Monats- und Tageszahl enthält.
|
Die der Funktion übergebenen Werte werden zunächst in Integer-Werte umgewandelt.
Tritt hier kein Fehler auf, wird mit der DateSerial-Funktion ein Datum erzeugt
und anschließend mit den VBA-Funktionen Year, Month und Day verglichen,
ob die Werte mit den Integer-Werten übereinstimmen. Wenn dem so ist, dann handelt
es sich um das Datum, das bei der Eingabe als Datum beabsichtigt war, andernfalls wird davon
ausgegangen, dass dem Anwender ein Fehler unterlaufen ist.
|
|
|
Public Function IsDateValid_2(ByVal varYear As Variant, _
ByVal varMonth As Variant, ByVal varDay As Variant, _
Optional ByRef dtmDate As Date) As Boolean
Dim intYear As Integer
Dim intMonth As Integer
Dim intDay As Integer
Dim dtmDateSerial As Date
On Error Resume Next
intYear = CInt(varYear)
intMonth = CInt(varMonth)
intDay = CInt(varDay)
If Err.Number = 0 Then
dtmDateSerial = DateSerial(intYear, intMonth, intDay)
If Err.Number = 0 Then
If Year(dtmDateSerial) = intYear Then
If Month(dtmDateSerial) = intMonth Then
If Day(dtmDateSerial) = intDay Then
dtmDate = dtmDateSerial
IsDateValid_2 = True
End If
End If
End If
End If
End If
On Error GoTo 0
End Function
|
|
|
|
|
Dim dtmDate As Date
If IsDateValid_2(txtYear.Text, txtMonth.Text, _
txtDay.Text, dtmDate) = True Then
MsgBox Format$(dtmDate, "Long Date")
End If
If IsDateValid_2(2004, 11, 3, dtmDate) = True Then
MsgBox Format$(dtmDate, "Long Date")
End If
|
|
|
|
|
|
Im Download befindet sich auch ein Excel/VBA-Beispiel.
|
|
Windows-Version |
95 |
 |
|
98 |
 |
|
ME |
 |
|
NT |
 |
|
2000 |
 |
|
XP |
 |
|
Vista |
 |
|
Win
7 |
 |
|
|
VB-Version |
VBA 5 |
 |
|
VBA 6 |
 |
|
VB 4/16 |
 |
|
VB 4/32 |
 |
|
VB 5 |
 |
|
VB 6 |
 |
|
|
|
Download (28,1
kB)
|
Downloads bisher: [ 1429 ]
|
|
|