Tijden optellen

Het werken met tijden in Access is vaak een heikele kwestie. Velden van het type datum/tijd zijn bedoeld om datums en/of tijdstippen vast te leggen. Vaak gebruiken mensen zo'n veld echter om een tijdsduur vast te leggen. Het veld wordt dan bijvoorbeeld gebruikt om het aantal gewerkte uren per dag vast te leggen (08:30, terwijl hier eigenlijk staat: half negen in de ochtend).
Dat levert dan problemen op, zeker als je met het veld gaat rekenen. Een van de problemen is dat een tijdveld per definitie niet groter kan zijn dan 23:59 uur.
Hoewel feitelijk dus niet correct, is er wel wat te zeggen voor het ge- c.q. misbruiken van datum/tijdvelden voor tijdstippen. Je hebt een mooie opmaak en bent van de nodige validatie-ellende verlost.

Om het rekenen met tijdvelden (waarin tijdsduren staan) mogelijk te maken heb ik twee functies gemaakt. Deze functies zijn vergelijkbaar met de standaard domeinfuncties die Access kent (DSum, DCount etc.). Ook in mijn functies geef je drie parameters op: het veld dat je wilt sommeren, de tabel waar het veld in staat en (optioneel) criteria waaraan de op te tellen records moeten voldoen.

De eerste functie levert een tekstveld op met de opmaak HH:MM:SS. Het is een tekstveld omdat het berekende totaal groter kan zijn dan 23:59:59. Je kan dus niet rekenen met het resultaat van de functie.
De functie ziet er zo uit:

Function SomTijdenUMS(Veld As String, Tabel As String, Optional Criteria As String) As String
Dim Uren As Long
Dim Min As Long
Dim Sec As Long

Sec = Nz(DSum("DatePart('s'," & Veld & ") + " _
     & "DatePart('n'," & Veld & ")*60 + " _
     & "DatePart('h'," & Veld & ")*3600", Tabel, Criteria), 0)

Uren = Int(Sec / 3600)
Sec = Sec - (3600 * Uren)
Min = Int(Sec / 60)
Sec = Sec - (60 * Min)

SomTijdenUMS = Uren & ":" & Format(Min, "00") & ":" & Format(Sec, "00")
End Function

Zoals gezegd kan je met de uitkomst van deze functie niet rekenen; hij levert alleen een opgemaakt tekstveld op.
Voor het geval je wel wilt kunnen rekenen met de berekende totaaltijd, heb ik een aangepaste functie gemaakt. Deze levert een aantal uren als decimaal getal op. Dat getal zou je dus bijvoorbeeld met een tarief (per uur) kunnen vermedigvuldigen.
De tweede functie werkt zo:

Function SomTijdenU(Veld As String, Tabel As String, Optional Criteria As String) As Single
Dim Sec As Long

Sec = Nz(DSum("DatePart('s'," & Veld & ") + " _
     & "DatePart('n'," & Veld & ")*60 + " _
     & "DatePart('h'," & Veld & ")*3600", Tabel, Criteria), 0)

SomTijdenU = Round(Sec / 3600, 2)
End Function

In de voorbeelddatabase heb ik een tabel gemaakt waarin het aantal bestede uren per medewerker per dag geregistreerd kan worden.

Op het formulier staan twee knoppen waarmee de eerste functie (opgetelde tijden als string weergeven) aangeroepen wordt. Je berekent daarmee de totalen van afdeling A respectievelijk B. Daarmee demonstreer ik meteen hoe je een conditie kunt gebruiken bij het aanroepen van de functie. De code onder de knop "Totaal A" is:
Me.Refresh
MsgBox "Het aantal uren voor Afdeling A bedraagt: " & _
SomTijdenUMS("Uren", "Boekingsregel", "Afdeling='A'"), vbInformation, "Aantal uren (A)"

De knop "Totaal uren" maakt gebruik van de tweede functie (totaal aantal uren als decimaal getal). Hier is geen conditie van toepassing en geef ik dus maar twee parameters mee. Onder de knop zit:
Me.Refresh
MsgBox "Het totaal aantal uren bedraagt: " & _
SomTijdenU("Uren", "Boekingsregel"), vbInformation, "Aantal uren (totaal)"