Programm ändern Schritt 5

Ein VBA-Programm ändern: Alter berechnen

Nachdem wir nun die Eingaben plausibilisiert haben, können wir anhand des Geburtsdatums (sofern vorhanden) das Alter errechnen.

Im einfachsten Fall müssen wir lediglich das Jahr ermitteln und vom aktuellen Jahr abziehen. Korrekt ist es jedoch, auch Monate und Tage zu berücksichtigen, um auch das aktuell korrekte Alter zu ermitteln.

Lösung für „den Hausgebrauch“ (simple Lösung)

In diesem Fall wird lediglich das Jahr als Basis des Alters benutzt, auch wenn das bedeutet, das Alter falsch zu berechnen, da der Geburtstag noch nicht erreicht ist. Bevor wir hier nun wieder mit Stringfunktionen versuchen, das Jahr zu extrahieren (das wäre: Mid$(sDate, 7, 4)), benutzen wir hierzu zwei weitere VBA-Funktionen, die uns diese Arbeit abnehmen.

Zunächst müssen wir aus dem String mit dem Geburtsdatum einen „echten“ Datumswert erzeugen.

Dazu stellt uns VBA die Konvertierungsfunktion CDate() zur Verfügung. Dieser Funktion wird als Argument der uns bekannte Datumsstring übergeben und wir erhalten den konvertierten String vom Typ Date zurück.

Beispiel:
    Dim sDatum  As String
    Dim dtDatum As Date
 
    sDatum = "01.01.1970"
    dtDatum = CDate(sDatum)

Nachdem wir das Geburtsdatum als „echtes“ Datum zur Verfügung haben, können wir mit einer der verfügbaren Datumsfunktionen von VBA das Jahr ermitteln. In diesem Fall benötigen wir die Year-Funktion. Dieser Funktion wird ein Datum übergeben und man erhält als Rückgabewert das Jahr.

Jahr = Year(dtDatum)

Nachdem wir das Jahr des Geburtstags ermittelt haben, benötigen wir noch das aktuelle Jahr für den Vergleich. Auch hierzu können wir die Year()-Funktion benutzen, nur müssen wir jetzt das Tagesdatum übergeben.

VBA stellt uns hier die Funktion Date() zur Verfügung, die das aktuelle Datum übergibt. Für unser Beispiel bedeutet das:

  Dim dtDate As Date
  dtDate = CDate(txtGebDatum.Value)
  MsgBox "Sie sind/werden " & Year(Date) - Year(dtDate) & " Jahre alt!

In dieser Hinweisanzeige werden verschiedene Informationen zu einem Text zusammengefasst (=konkateniert), in dem die einzelnen Hinweis“teile“ mit dem &-Zeichen zusammengefügt werden!

Unsere Routine hat sich wie folgt verändert:

Beispiel:

' Gültigkeitsüberprüfung des Datums
Private Sub txtGebDatum_AfterUpdate()
 
    Dim sDate   As String
    Dim dtDate  As Date
 
   'Eingabe "trimmen"
    sDate = Trim$(txtGebDatum.Value)
   'Länge 0 prüfen
    If Len(sDate) > 0 Then
       'Länge <> 10 prüfen
        If Len(sDate) <> 10 Then
           'Hinweis anzeigen
            MsgBox "Ungültige Datumseingabe. " & _
              "Bitte das Format TT.MM.JJJJ verwenden!"
           'Eingabefeld leeren
            txtGebDatum.Value = ""
        Else
           'Gültigkeit des Datums überprüfen
            If Not IsDate(sDate) Then
               'Hinweis anzeigen
                MsgBox "Ungültige Datumseingabe. " & _
                  "Bitte das Format TT.MM.JJJJ verwenden!"
               'Eingabefeld leeren
                txtGebDatum.Value = ""
            ' An dieser Stelle wurde ein
            ' neuer Else-Zweig eingefügt!
            Else
                dtDate = CDate(sDate)
                MsgBox "Sind sind/werden " & _
                  Year(Date) - Year(dtDate) & " Jahre alt!"
            End If
        End If
    End If
 
End Sub

Hier wurde jetzt die Deklaration der Variablen dtDate vom Type Date hinzugefügt.
Die Deklaration von Variablen (Dim) erfolgt in der Regel zu Beginn einer jeden Routine.
Weiterhin wurden die Errechnung und die Anzeige des Alters in einem neuen Else-Zweig dort eingefügt, wo die Eingabe bereits entsprechend plausibilisiert wurde.

Der Nachteil dieser Lösung liegt in dem Umstand, dass jedes Mal diese Altersberechnung und –anzeige erfolgt, wenn diese Routine aufgerufen wird. Das ist nicht sehr elegant und sollte daher an anderer Stelle erfolgen. Aus diesem Grund werden wir die Berechnung des Alters in eine eigene Funktion auslagern.

Eine Funktion gibt – im Gegensatz zu einer sog. Sub-Routine – einen Wert zurück. In diesem Fall möchten wir der Funktion den Eingabestring übergeben und das errechnete Alter zurückbekommen.

Derartige Funktionen müssen wir selbst erstellen; daher schreiben wir an eine „freie“ Stelle im Codefenster:

' Neue Funktion Alter
Private Function Alter(ByVal dtGebDat As Date) As Long
 
End Function

Die Funktion Alter erhält als Argument einen String (mit der Datumseingabe) und gibt einen numerischen Wert (hier: Typ Long) zurück.

Da es sich um eine eigenständige Funktion handelt, sollten wir innerhalb der Funktion (selbst nochmals) den Stringwert plausibilisieren, da wir nie davon ausgehen dürfen, dass dies bereits geschehen ist und wir „blind“ darauf vertrauen können.

Demzufolge stellt sich diese (vereinfachte) Altersberechnungsfunktion wie folgt dar:

Beispiel:

' Einfache Altersberechnung
Private Function Alter(sDatum As String) As Long
 
  Dim dtDate As Date
  sDatum = Trim$(sDatum)
 
  If Len(sDatum) = 10 Then
    If IsDate(sDatum) Then
      dtDate = CDate(sDatum)
      Alter = Year(Date) - Year(dtDate)
    End If
  End If
 
End Function

Nur wenn alle Plausibilitäten erfolgreich durchlaufen wurden, wird das Alter errechnet und zurückgegeben. In allen anderen Fällen erhält man als Rückgabewert 0, dem Standardwert für den Long-Datentyp.

Da wir jetzt eine eigene Funktion für die Altersberechnung haben, müssen wir den zuvor eingefügten Else-Zweig (s.o.) wieder entfernen.

Diese Lösung hat bekanntermaßen den Nachteil, das Alter nicht unbedingt korrekt zu errechen, da lediglich das Jahr und nicht die Monate und Tage berücksichtigt werden.

HinweisHinweis: Es steht jetzt jedem frei, dies zu ändern und die Funktion entsprechend anzupassen, in dem die Tage und der Monat ermittelt werden, um diese Werte gegen das aktuelle Tagesdatum zu prüfen, um das korrekte Alter zu ermitteln...

ExpertentippProfilösung: Die nachfolgende Lösung ist für fortgeschrittene VBA-Programmierer gedacht und wird daher nicht weiter kommentiert:

Beispiel:

' Profilösung
Private Function Alter(ByVal dtGebDat As Date) As Long
 
    Alter = Year(Now) - Year(dtGebDat) + _
      (DateSerial(Year(Now), _
       Month(dtGebDat), _
       Day(dtGebDat)) > Now)
 
End Function