Schlagwort: zeit

Automatische Arbeitszeiterfassung

Automatische Arbeitszeiterfassung in Excel

Basierend auf der Arbeitszeiterfassung, die komplett von Hand auszuführen ist, war der nächste Ansporn, das ganze zu automatisieren. Gesagt, getan und eine Woche später konnte ich nun mit einer umfangreich programmierten Exceldatei prahlen. Die Funktionen möchte ich hier im einzelnen erklären, zuerst hier aber in einer Textdatei der Code aus allen Worksheets, UserForms und Modulen, damit ihr euch sicher sein könnt, dass ihr euch durch meine Datei keinen Virus auf den Computer ladet 😉

Ein kleiner Disclaimer

Ich bin kein Programmierer, schon gar kein Informatiker. Wer sich unter diesen Aspekten den Code anschaut, wird wahrscheinlich die Hände über dem Kopf zusammenschlagen. Das ist voll okay und mir prinzipiell egal, denn bei mir heiligt der Zweck die Mittel. Solange etwas funktioniert, ist das okay. Wenn nicht, fixe ich es. Natürlich kann man den Code optimieren, aber solange er läuft, bin ich zufrieden.
Nun denn, wollen wir die Datei mal öffnen und uns die einzelnen Fenster betrachten:

Die Meldung, falls bereits der aktuelle Tag ausgefüllt wurde und keine weiteren Daten fehlen.

Öffnet man die Exceldatei, wird in der Workbook_Open-Prozedur das Ausgangsblatt (Tabellenblatt „Jahresübersicht“) gereinigt und die für das aktuelle Jahr geleisteten Arbeits- und Überstunden in einer Ansicht angezeigt, sowie auch die bisherigen Urlaubs- und Krankheitstage. Die aktuellen Überstunden stehen ebenfalls auf den ersten Blick sichtbar drin. Die Kalenderwochen werden nach der ISO-Norm 8601 (früher DIN 1355-1) berechnet, sodass die Erkennung der 52. und 53. Kalenderwoche ohne Probleme von statten geht. An dieser Stelle, als ich diese Zeilen schrieb, merkte ich dann aber, dass ich die Anzeige der 53. KW im Tabellenblatt gar nicht berücksichtigt habe. Dies ist nun aber der Fall. Sollte ein Jahr eine 53. KW haben, so wird diese angezeigt und auch die Anzahl der Stunden eingetragen. Nachdem dies geschehen ist, schaut die Prozedur nach, ob für den heutigen Tag Eintragungen vorhanden sind. Je nachdem wird eine Meldung angezeigt, auch, wenn in der Vergangenheit Tage ohne Eintrag vorhanden sind. In meinem Fall wird das obenstehende Fenster angezeigt. Auch die gesetzlichen Feiertage werden erkannt, in meiner Datei aber nur die für Sachsen. Man kann sich natürlich auch alle anderen Feiertage einbinden. Wo das geht, zeige ich etwas später.
Nach bestätigen dieser Meldung kommen wir in das eigentliche „Hauptmenü“ der Datei. Die Menüführung mag etwas komisch erscheinen, hat aber den Hintergrund, dass die wichtigsten Funktionen gebündelt im ersten Fenster erscheinen und alle Zusatzfunktionen auf weiteren Fenstern liegen. Die Datei soll ja im Grunde nur die Arbeitszeit erfassen.

Das eigentliche Hauptmenü der Datei

Hier haben wir nun das Hauptmenü erreicht. Wie man sieht, sind zwei Felder deaktiviert („ausgegraut“), was der Tatsache geschuldet ist, dass hier in dem Beispiel bereits Daten im aktuellen Tag erfasst wurden. Bei „Erfasste Zeit“ sieht man die aktuelle Uhrzeit. Diese wird auch einmalig beim Öffnen abgefragt und in die Caption des Option Buttons geschrieben, sodass diese fest bleibt. Im Feld „Eigene Zeit“ kann man eine individuelle Erfassung durchführen. Haben wir – wie in diesem Beispiel – bereits Arbeitsbeginn und Feierabend erfasst, können wir nur noch die Pausenzeit eintragen. Falls es für den aktuellen Tag noch gar keine Eintragung gibt, erscheinen nur die Optionen der erfassten und eigenen Zeit.
Nun haben wir hier noch drei Buttons. „Erfassen“ schreibt entweder die erfasste oder selbst eingetragene Zeit in den aktuellen Tag und fragt, ob man die Datei nun schließen möchte. Das ist die eigentliche Hauptfunktion. „Beleg drucken“ bringt ein kleines Fenster mit einem Dropdown-Feld, in dem alle Sheets, die eine Jahresliste enthalten, zur Auswahl stehen und man das jeweilige Jahr als PDF speichern kann. Wählen wir als Option „Urlaub / Krankheit“ und gehen auf „Erfassen“, kommen wir in folgendes Fenster:

Das Fenster zum Auswählen der Urlaubs- und Krankheitstage

In diesem Fenster werden in zwei Listenboxen die Tage des aktuellen Jahres aufgelistet und man kann per Mehrfachauswahl die jeweiligen Tage als Urlaub oder Krank markieren. In meinem Beispiel geht das Jahr 2019 in der Datei erst mit dem 12. August los.

Das Fenster, dass sich hinter dem Button „Daten editieren / ansehen“ verbirgt

Haben wir im „Hauptmenü“ den Button „Daten editieren / ansehen“ gewählt, bekommen wir das obige Fenster zu sehen, wobei der untere Rahmen beim Start noch aufgeblendet ist. Man kann einerseits sich neue Tabellenblätter generieren lassen, die nach dem letzten Jahr hinzugefügt werden. Als Beispiel: ist das letzte Jahr in der Excel 2020 und man lässt sich für die nächsten drei Jahre Tabellenblätter generieren, so erhält man die Tabellenblätter für 2021, 2022 und 2023. Es werden dabei wieder nur die Arbeitstage (Montag bis Freitag) generiert, gleichzeitig aber in der Spalte „Bemerkung“ eingetragen, ob es sich um einen gesetzlichen Feiertag (in Sachsen) handelt. Wählt man den Button „Arbeitszeiten anpassen / ansehen“, kommt folgendes Fenster:

Die Option „Arbeitszeiten anzeigen / editieren“

Hier wird die absurde Menüstruktur ersichtlich, denn wollen wir die Datei öffnen und uns einfach nur die Daten ansehen, müssen wir uns bis zu diesem Fenster durchklicken und die Option „Bearbeiten“ wählen. Alle Fenster, die wir bisher gesehen haben, können wir auch nicht über das Kreuz in der oberen rechten Ecke schließen. Das ist so gewollt, da die Standardprozedur Öffnen Erfassen Schließen sein soll.
Wählen wir im obigen Fenster „Anzeigen“, bekommen wir wieder alle vorhandenen Tabellenblätter mit Jahreslisten beinhaltend aufgelistet und können uns ein Jahr auf der Startseite anzeigen lassen. Nachdem dieses generiert wurde, bleibt die Exceldatei aber offen. Das dient eben nur der Anzeige.
Beim Schließen der Exceldatei wird das erste Blatt ebenfalls gecleant, also alle Werte gelöscht. Das ist einfach ein Sicherheitsmechanismus, der meiner Programmierung geschuldet ist, weil ich die Stunden von Zelle zu Zelle addiere. Ein Blick in den Programmcode erklärt dies.

Feiertage für andere Bundesländer

An dieser Stelle möchte ich noch kurz auf die Funktion der Erkennung von Feiertagen eingehen. Zuerst der Programmcode:

Public Function IstFeiertag(datum) As Boolean
    Select Case Left(datum, 6)
        Case "01.01."
            IstFeiertag = True
        Case "01.05."
            IstFeiertag = True
        Case "03.10."
            IstFeiertag = True
        Case "31.10."
            IstFeiertag = True
        Case "25.12."
            IstFeiertag = True
        Case "26.12."
            IstFeiertag = True
        Case Left(Bettag(Right(datum, 4)), 6)
            IstFeiertag = True
        Case Left(DateAdd("d", Ostersonntag(Right(datum, 4)), "01.03." & Right(datum, 4)), 6)
            IstFeiertag = True
        Case Left(DateAdd("d", Ostersonntag(Right(datum, 4)) - 3, "01.03." & Right(datum, 4)), 6)
            IstFeiertag = True
        Case Left(DateAdd("d", Ostersonntag(Right(datum, 4) + 38), "01.03." & Right(datum, 4)), 6)
            IstFeiertag = True
        Case Left(DateAdd("d", Ostersonntag(Right(datum, 4) + 49), "01.03." & Right(datum, 4)), 6)
            IstFeiertag = True
        Case Else
            IstFeiertag = False
    End Select
End Function

Ich gebe in meine Funktion ein Datum ein und frage ab, ob es ein Feiertag ist (IstFeiertag = True) oder nicht (IstFeiertag = False). Man kann dies natürlich anpassen und den Namen des Feiertags ausgeben, mir reichte aber ein boolscher Wert. Weiterhin lassen sich hier natürlich entsprechend andere Feiertage einstellen. Man ändert den jeweiligen Case, z.B. „01.11.“ für Allerheiligen, das in Baden-Württemberg, Bayern, Nordrhein-Westfalen, Rheinland-Pfalz und dem Saarland ein Feiertag ist. Da dies als Funktion implementiert wurde, muss die Änderung nur einmal erfolgen und ist somit global für die ganze Datei gültig.
Hier fällt übrigens auch eine weitere Funktion auf: „Ostersonntag“. Das ist eine weitere Funktion die ich mir geschrieben habe und beinhaltet nur die Osterformel nach Gauß, die 1997 durch Heiner Lichtenberg für die computergestützte Berechnung angepasst wurde:

Public Function Ostersonntag(jahr)
    k = jahr \ 100
    m = 15 + (3 * k + 3) \ 4 - (8 * k + 13) \ 25
    s = 2 - (3 * k + 3) \ 4
    a = jahr Mod 19
    d = (19 * a + m) Mod 30
    r = (d + a \ 11) \ 29
    OG = 21 + d - r
    SZ = 7 - (jahr + jahr \ 4 + s) Mod 7
    OE = 7 - (OG - SZ) Mod 7
    Ostersonntag = OG + OE
End Function

Hierbei gebe ich lediglich der Funktion das Jahr und die spuckt mir das Datum des Ostermontags aus. Das habe ich erst festgestellt, nachdem ich die Funktion so genannt und überall darauf bezogen habe. Macht aber nichts, da ich ja um diesen Umstand weiß 😉 Die Funktion errechnet ein Märzdatum, also z.B. den 53. März. Den Zahlenwert 53 kann man dann mit der DateAdd-Funktion auf den 01.03. aufaddieren und erhält dann das richtige Aprildatum. Alle anderen Daten der Karwoche ergeben sich dann daraus. Eine dritte Funktion, die ich mir gebaut habe, ist die Errechnung des Buß- und Bettagsdatums, das immer der letzte Mittwoch vor dem 23. November ist:

Public Function Bettag(jahr)
    hilf = "23.11." & jahr
    If Weekday(hilf, vbMonday) = 3 Then
        Bettag = DateAdd("d", -7, hilf)
    Else
        Do
            hilf = DateAdd("d", -1, hilf)
        Loop Until Weekday(hilf, vbMonday) = 3
        Bettag = hilf
    End If
End Function

Falls der 23.11. selbst ein Mittwoch ist, fällt der Buß- und Bettag auf den 16.11., ansonsten entsprechend einen Tag davor, spätestens auf den 22.11.

So, nach allerhand Erklärung soll es nun hier die Datei zum Download geben. Bei Anregungen oder Fehlern freue ich mich über einen Kommentar oder eine E-Mail. 🙂

Das Problem mit der fehlenden Bibliothek

Leider kann es beim ersten Öffnen zu einem Fehler kommt. Dieser hängt mit einem fehlerhaften Bezug zu einer Bibliothek zusammen. Wie genau das passieren konnte, weiß ich nicht, allerdings gibt es ein kleines Workaround, das einmalig auszuführen ist:

Arbeitszeiterfassung in Excel

Arbeitszeiterfassung in Excel

Meine bessere Hälfte bat mich darum, ihr eine von ihr angelegte Exceldatei zu überarbeiten. Ihr Wunsch: sie trägt nur die Arbeits- und Pausenzeiten ein und bekommt dann ausgerechnet, wie viele Stunden sie pro Tag, pro Woche, pro Monat und wie viele Überstunden gearbeitet hat. Problem an der ganzen Sache: sucht man im Internet nach „Uhrzeiten in Excel berechnen“, so bekommt man nicht hundertprozentig das, was es hier umzusetzen gilt. Das Ergebnis soll nämlich nicht im Format hh:mm (Stunden und Minuten) sein, sondern als Fließkommazahl (z.B. 8,75 Stunden). Das war für den Anfang etwas tricky, aber die Lösung ist nicht wirklich schwer. Einzig die Formel in Excel kann etwas aufgebläht wirken. Da habe ich aber keine Ahnung, ich bin schließlich kein Informatiker 😀

Beginnen wir also! Zur Vorbereitung legen wir uns fünf Spalten an: Beginn, Ende, Pause, Arbeitszeit und eine fünfte Spalte, zu der ich später noch komme. Optional kann man vor der Spalte „Beginn“ sich noch das Datum notieren. In meinem Fall sieht das dann erstmal so aus:

Vorbereitung der Spalten für die Arbeitszeiterfassung
Vorbereitung der Spalten für die Arbeitszeiterfassung

Wer mag, kann sich nun noch die erste Zeile fixieren, sodass man beim Scrollen durch das Tabellenblatt später noch die Spalten zuordnen kann. Okay, fünf Spalten sind jetzt nicht die Welt, aber hierbei können wir gleich diese Funktion noch einmal üben. Wir klicken dazu links auf die erste Zeile, also auf die in meinem Bild grau hinterlegte grüne Eins, die neben der Zelle A1 ist, klicken auf den Reiter „Ansicht“, dann „Fenster fixieren“ und wählen die Option „Oberste Zeile fixieren“. Nun haben wir eine feste Zeile, die beim Scrollen immer oben angezeigt wird.

Damit die Anzeige der Arbeitszeiten und die spätere Berechnung wie gewünscht reibungslos funktioniert, müssen wir uns die jeweiligen Zellen formatieren. Für das Datum kann man mehrere Formate nutzen. In meinem Beispiel nutze ich das Format Tag, DD. Monat YYYY, zum Beispiel: Montag, 12. August 2019. Um dies einzustellen klicken wir in die Zelle, gehen im Reiter „Start“ in dem Formatierungsblock auf den Pfeil rechts unten (im Bereich „Zahl“), wählen in dem neu geöffneten Fenster die Kategorie „Datum“ und wählen das zweite Format in der Liste „*Mittwoch, 14. März 2012“. Nachdem wir das Fenster mit einem Klick auf „OK“ geschlossen haben, tragen wir in die Zelle A2 ein Datum ein, z.B. „12.08.2019“, und bestätigen mit Enter. Die Zelle sollte nun den Inhalt „Montag, 12. August 2019“ tragen und sich automatisch auf die erforderliche Breite eingestellt haben. Die Zellen B2 und C2 können wir gemeinsam formatieren mit den eben genannten Schritten, nur wählen wir hier die Kategorie „Uhrzeit“ und das Format „13:30“ aus. Einzugeben ist die Uhrzeit in diesem Format, wobei die Stundenzahlen von null bis neun ohne vorangestellte null eingetragen werden können. Die Zelle D2 für die Pausenzeit, die ich hier in vollen Minuten angebe, stellen wir als Zahl ohne Nachkommastellen ein, die Zelle E2 als Zahl mit zwei Nachkommastellen. Im Feld E2 bleiben wir nun und geben die Formel ein. Entweder beginnen wir gleich mit dem Gleichheitszeichen oder gehen oben in die sogenannte Bearbeitungsleiste. Die Formel zur Berechnung lautet:

=WENNFEHLER(STUNDE(C2-B2-ZEIT(0;D2;0))+((MINUTE(C2-B2-ZEIT(0;D2;0))/100)*100/60);0)

Erklärung der Formel: Eingeleitet wird sie mit einer Fehlerabfrage „WENNFEHLER()“. Das verhindert, dass bei fehlenden Zelleninhalten der Text „#ZAHL!“ in der Ergebniszelle erscheint. Das ist für spätere Berechnungszwecke wichtig. Das Ergebnis selbst ist an sich eine Summe aus den vollen Stunden und den Minuten. In dem Teil STUNDE() wird die Differenz aus End-, und Anfangs- und Pausenzeit gebildet. Da ich die Pausenzeit hier in Minuten angebe, müssen diese erst in eine Zeit umgerechnet werden. Das klingt an dieser Stelle komisch, hat aber den Hintergrund, dass Excel Uhrzeiten in Kommazahlen umrechnet und mit diesen operiert. Die Formel ZEIT() benötigt also die Parameter Stunden, Minuten und Sekunden und gibt eine Kommazahl aus. Beispiel: ZEIT(0;30;0) gibt den Wert 0,0208333… zurück.
Bei den Minuten machen wir im Grunde das Gleiche, jedoch müssen wir hier noch etwas umrechnen. Da wir als Ergebnis eine Kommazahl haben wollen, darf der Teil nach dem Komma maximal den Wert 100 haben, also müssen wir erstmal durch 100 teilen. Danach rechnen wir diesen Wert über eine umgestellte Verhältnisgleichung von Minuten in den gleichwertigen Teil von 100 um. Kurz gesagt: wenn 15 Minuten eine Viertelstunde sind, ergibt das 0,25.
Nun können wir zum Test die Werte 7:30 als Beginn, 16:30 als Ende und 60 als Pause eingeben. Das Ergebnis sollte eine Arbeitszeit von acht Stunden sein.

Nun markieren wir die Zellen A2 bis E2 und packen an dem kleinen Quadrat am unteren rechten Ende des markierten Bereiches an und ziehen uns den Bereich auf die gewünschte Anzahl an Zeilen. In der Spalte F markieren wir nun die Zellen F2 bis F4, gehen im den Reiter  „Start“ im Bereich „Ausrichtung“ auf „Verbinden und zentrieren“ und wiederholen das mit den Zellen F5 und F6. In die Zelle F1 kann man nun sowas wie „Wochen- und Überstunden“ eintragen. In den Zellenbereich F2 bis F4 klicken wir hinein und bilden die Summe der in einer Woche geleisteten Arbeitszeit. Für die Erste Woche ist das z.B. =SUMME(E2:E6). Die Eingabe bestätigen wir mit Enter. Für die Überstunden geben wir im Zellenverbund F5 F6 die Formel =SUMME(E2:E6)-40 ein, alternativ =E2-40. Falls die Wochenarbeitszeit abweicht, ist die 40 hier anzupassen 😉

Für wen das ein Krampf ist, das alles hier abzuarbeiten, der kann sich hier eine Beispieldatei herunterladen.

  Arbeitszeiterfassung