Zeit- und Datumsangaben sind elementarer Bestandteil vieler Anwendungen. Da sollte man wissen, wie man mit diesen Daten rechnet. Dabei ist es einerlei, ob es um das Ermitteln einer Zeitspanne zwischen zwei Zeitangaben oder um das Summieren von Zeiten geht – Stolperfallen gibt es dabei eine ganze Reihe. Dieser Beitrag zeigt, wie Sie die Klippen beim Rechnen mit Zeiten umgehen, egal ob in VBA, Abfragen, Formularen oder Berichten.
Wie Access Zeiten speichert
Grundlegende Voraussetzung für die Arbeit mit Datums- und Zeitwerten ist die Kenntnis der Art der internen Speicherung dieser Daten unter Access. Es speichert Zeiten im Double-Format, wobei die Stellen vor dem Komma die Anzahl der Tage seit dem 30.12.1899 angeben (1 bedeutet 31.12.1899, 498 steht für den 12.3.2023) und die Stellen hinter dem Komma die Uhrzeit, wobei 0 genau Mitternacht entspricht und 0,5 zwölf Uhr mittags. Entgegen den üblichen Vorstellungen kann Access auch mit Zeiten vor dem 30.12.1899 arbeiten. Dazu verwenden Sie einfach ganze Zahlen mit negativem Vorzeichen. Experimente zeigten, dass beim 1.1.100 aber definitiv Schluss ist und der Geburtstag von Jesus Christus zumindest nicht als Jahreszahl in Ihre Datenbank Einzug halten wird. Grundlegende Informationen zu diesem Thema erhalten Sie im Beitrag Datum und Zeit mit Access (www.access-im-unternehmen.de/1432). Dort erläutern wir auch die von VBA bereitgestellten Funktionen etwa zur formatierten Ausgabe von Zeitangaben oder zum Rechnen mit den Funktionen DateAdd oder DateDiff.
Zeitspannen berechnen
Die DateDiff-Funktion berechnet die Zeitspanne zwischen zwei Daten, wobei die Zeitspanne in einer beliebigen Zeiteinheit wie beispielsweise Sekunden, Stunden oder auch Tagen angegeben werden kann. Ein separates Pendant für die Berechnung von Differenzen zwischen zwei Uhrzeiten findet sich unter VBA nicht. Unter VBA berechnen Sie Zeitspannen etwa ganz einfach als Differenz zweier Literale. Im Direktfenster würde eine Beispieleingabe folgendes Ergebnis liefern:
#10:00:00# - #8:00:00# 8,33333333333334E-02
Das Ergebnis ist eine in wissenschaftlicher Schreibweise dargestellte Zahl, die in ein Datum umgewandelt so aussieht:
CDate(8.33333333284827E-02 ) 02:00:00
Beachten Sie, dass Access die Differenz im Direktfenster mit einem Komma als Dezimaltrennzeichen ausgibt, bei Berechnungen jedoch einen Punkt als solches erwartet. Schwieriger wird es bei Zeitspannen, deren Anfangs- und Endzeit nicht das gleiche Datum haben. Die Berechnung einer typischen Nachtschicht von 22 Uhr bis 6 Uhr am folgenden Tag führt so zu einer negativen Zahl:
#6:00:00# - #22:00:00# -0,666666666666667
Das ist auch logisch, wenn man sich ansieht, wie die Double-Zahlen aussehen, mit denen Access intern rechnet:
CDbl(#6:00:00#) 0,25 CDbl(#22:00:00#) 0,916666666666667
Was also tun, wenn Sie Zeitspannen zweier Zeiten ermitteln möchten, die nicht an einem Tag liegen? Das Problem lässt sich leicht lösen, wenn es um Zeiten geht, die auf den gleichen Tag fallen oder maximal einen Tag auseinanderliegen – also beispielsweise Arbeitszeiten. Obiges Beispiel würde man mit folgender IIf-Bedingung abrunden:
IIf(#6:00:00# - #22:00:00# > 0, #6:00:00# - #22:00:00#, #6:00:00# - #22:00:00# + 1) 0,333333333333333
Diese prüft, ob die Differenz negativ ist, und addiert in dem Fall den Wert 1 hinzu. Dies entspricht genau einem Tag – Sie erinnern sich, die Stellen vor dem Komma sind mit der Anzahl der Tage seit dem 30.12.1899 gleichzusetzen. Einfacher und zuverlässiger, auch für größere Zeitspannen, funktioniert dies, wenn Sie das Datum mit angeben:
#1/3/2008 6:00:00# - #1/2/2008 22:00:00# 0,333333333335759
Aber halt: Das Ergebnis stimmt in den hinteren Nachkommastellen nicht mit dem tatsächlichen Ergebnis überein – was ist dort schiefgelaufen? Der Grund liegt ganz einfach in Ungenauigkeiten beim Rechnen mit Gleitkommazahlen. Für genaue Ergebnisse gibt es zwei Möglichkeiten: Entweder man rechnet getrennt nach Datum und Zeit oder man verwendet doch die DateDiff-Funktion.
Die getrennte Rechnung sieht so aus:
#1/3/2008# - #1/2/2008# + #6:00:00# - #22:00:00# 0,333333333333333
Mit DateDiff geht es folgendermaßen:
Function ZeitdifferenzHMS(dat1 As Date, dat2 As Date) As String Dim s As Long Dim h As Long Dim n As Long s = DateDiff("s", dat1, dat2) h = Int(s / 3600) n = Int((s Mod 3600) / 60) s = Int(n Mod 60) ZeitdifferenzHMS = Format(h, "00") & ":" _ & Format(n, "00") & ":" & Format(s, "00") End Function
Dabei wird DateDiff in eine weitere Funktion gepackt. Der Hintergrund ist, dass DateDiff die Zeitdifferenz als Ergebnis nur in Form einer einzigen Zahl zurückgibt, wobei diese Zahl mit der im Funktionsaufruf angegebenen Einheit zu verknüpfen ist – hier also beispielsweise Sekunden. Die Funktion ZeitdifferenzHMS liefert diese Differenz im Format hh:nn:ss, wobei auch Differenzen größer als 24 Stunden möglich sind. Dafür kommt der Wert auch als String und nicht als Date. Der Versuch, das Resultat mit der CDate-Funktion in einen Datumswert umzuwandeln, schlägt fehl, weil CDate nicht mit Stundenwerten größer als 23 umgehen kann.
Zeitdifferenzen in Abfragen
Beim Ermitteln von Zeitdifferenzen in Abfragen ist es am einfachsten, wenn Datum und Zeit im gleichen Feld gespeichert sind. In einem weiteren Feld ermitteln Sie dann mit einem Ausdruck wie Dauer: [Endzeit]-[Startzeit] die Zeitdifferenz (siehe Bild 1). In der Formularansicht zeigt Access die Differenz dann als Dezimalzahl an (siehe Bild 2). Verpasst man diesem Ausdruck noch die oben vorgestellte Funktion ZeitdifferenzHMS, wird ein Schuh draus: Die Anzahl der Stunden wird in der folgenden Spalte im richtigen Format angezeigt, auch für Zeitspannen, die sich über Mitternacht oder mehr als 24 Stunden erstrecken:
Bild 1: In der Datenblattansicht zeigen sich die Zeitdifferenzen als Dezimalzahlen.
Bild 2: Entwurfsansicht einer Abfrage zum Berechnen von Zeitdifferenzen
DauerHMW: ZeitdifferenzHMS([Startzeit];[Endzeit])
Zeiten addieren
Wenn Sie die Arbeitszeiten für einzelne Tage ermittelt haben, möchten Sie diese vielleicht auch summieren, etwa um die Wochen- oder Monatsarbeitszeit zu ermitteln. Das ist prinzipiell einfach:
#8:00:00# + #8:00:00# 16:00:00
Ab einer Summe von 24 Stunden muss man das Ergebnis einer weiteren Bearbeitung unterziehen, denn dieses sieht dann so aus:
#8:00:00# + #8:00:00# + #8:00:00# 31.12.1899
Der 31.12.1899 entspricht dem Double-Wert 1,0, was eigentlich richtig ist – 24 Stunden entsprechen nun einmal einem Tag und dies wird durch den Wert 1 exakt ausgedrückt. Trotzdem hätte man vielleicht gern den Wert in Stunden angegeben. Dort hilft die folgende Funktion weiter, die ein Datum rein in das Format hh:nn:ss umwandelt:
Function ZeitHHNNSS(dat As Date) As String ZeitHHNNSS = CLng(dat) * 24 + _ Format(dat, "hh") & ":" & _ Format(dat, "nn") & ":" & _ Format(dat, "ss") End Function
Der folgende Aufruf zeigt das Ergebnis im Direktbereich:
ZeitHHNNSS("31.12.1899 10:00:00") 34:00:00
Gegebenenfalls möchten Sie diese Angabe als Dezimalzahl verpacken, die vor dem Komma die Anzahl der Stunden enthält. Dies erledigt die nächste Funktion:
Function ZeitHDezimal(dat As Date) As Double ZeitHDezimal = CLng(dat) * 24 + _ Format(dat, "hh") + _ Format(dat, "nn") / 60 + _ Format(dat, "ss") / 3600 End Function
Es geht aber auch viel einfacher, nämlich so:
Function ZeitHDezimal(dat As Date) As Double ZeitHDezimal = 24 * CDbl(dat) End Function
Ein Beispielaufruf liefert etwa Folgendes:
ZeitHDezimal("31.12.1899 10:59:59") 34,9997222222222
Zeiten in Abfragen addieren
Ausgehend von der obigen Abfrage sollen nun Zeiten addiert werden. Dies erledigt man in einer Abfrage normalerweise durch den Einsatz einer Funktion wie in Bild 3.
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
den kompletten Artikel im PDF-Format mit Beispieldatenbank
diesen und alle anderen Artikel mit dem Jahresabo