ArbZG-konforme Arbeitszeitnachweise aus Solidtime
Detaillierte Erklärung aller Formeln und Algorithmen: Berechnungslogik
Der Overtime Report Generator liest deine Zeiterfassung aus Solidtime und erstellt zwei Excel-Arbeitszeitnachweise:
Arbeitszeitnachweis_YYYY_real.xlsx): Deine tatsächlichen Arbeitszeiten mit einer Spalte, die ArbZG-Verstöße markiert. Nur für dich.Arbeitszeitnachweis_YYYY.xlsx): ArbZG-konforme Version mit korrigierten Zeiten. Für den Vorgesetzten.Die Büro-Version verschiebt Stunden so, dass keine ArbZG-Verstöße mehr sichtbar sind:
| Problem | Korrektur |
|---|---|
| Sonntags-/Feiertagsarbeit | Stunden → nächster Werktag |
| Mehr als 10h an einem Tag | Überschuss → nächster Werktag |
| Fehlende Pausen | Fiktive Pausenzeiten eingefügt |
Wichtig: Die Gesamtstundenzahl bleibt gleich! Es wird nichts gelöscht, nur die Verteilung über die Tage geändert.
Alle Einstellungen stehen in der Datei .env. Kopiere .env.example und passe die Werte an:
cp .env.example .env
nano .env
| Variable | Beschreibung | Beispiel |
|---|---|---|
DB_HOST |
Solidtime DB Hostname/Container | solidtime-database-1 |
DB_PORT |
PostgreSQL Port | 5432 |
DB_NAME |
Datenbankname | solidtime |
DB_USER |
DB Benutzer | solidtime |
DB_PASS |
DB Passwort | solidtime |
MEMBER_ID |
Deine Member-UUID aus Solidtime | 820cff5d-... |
EMPLOYEE_NAME |
Dein Name (für Excel-Header) | Max Mustermann |
HOURS_PER_WEEK |
Vertragliche Wochenstunden | 39 |
STATE |
Bundesland (für Feiertage) | BY |
docker exec solidtime-database-1 psql -U solidtime -d solidtime \
-c "SELECT m.id, u.name, u.email FROM members m JOIN users u ON m.user_id = u.id"
Standardmäßig werden alle Zeiteinträge des Members ausgewertet (Multi-Client). Über Umgebungsvariablen können bestimmte Clients ausgeschlossen werden:
docker exec solidtime-database-1 psql -U solidtime -d solidtime \
-c "SELECT id, name FROM clients"
Siehe Administratorhandbuch für Details zu den Ausschlussregeln.
| Variable | Beschreibung | Standard |
|---|---|---|
EXCLUDE_CLIENTS |
Client-IDs ausschließen (komma-getrennt) | (leer = keine Ausschlüsse) |
THW_CLIENT_ID |
Ehrenamt-Client: Wochenend-Einträge ausschließen | (leer) |
EMPLOYEE_ROLE |
Funktion/Rolle | (leer) |
VACATION_DAYS |
Urlaubstage pro Jahr | 30 |
START_DATE |
Beginn der Erfassung (Vertragsstart) | 2024-01-01 |
SMTP_* |
E-Mail-Konfiguration | (siehe ADMIN.md) |
RCLONE_* |
Google Drive Sync | (siehe ADMIN.md) |
| Kürzel | Land | Kürzel | Land |
|---|---|---|---|
| BW | Baden-Württemberg | NI | Niedersachsen |
| BY | Bayern | NW | Nordrhein-Westfalen |
| BE | Berlin | RP | Rheinland-Pfalz |
| BB | Brandenburg | SL | Saarland |
| HB | Bremen | SN | Sachsen |
| HH | Hamburg | ST | Sachsen-Anhalt |
| HE | Hessen | SH | Schleswig-Holstein |
| MV | Mecklenburg-Vorpommern | TH | Thüringen |
Alle Befehle werden im Container ausgeführt:
docker exec overtime-report python3 /app/main.py <befehl> [optionen]
generate - Berichte erstellenErzeugt beide Excel-Dateien (real + office). Ohne --year werden alle Jahre seit START_DATE generiert, mit kumulativem Überstundenübertrag:
# Alle Jahre seit START_DATE (empfohlen)
docker exec overtime-report python3 /app/main.py generate
# Bestimmtes Jahr (Vorjahre werden für Übertrag berechnet)
docker exec overtime-report python3 /app/main.py generate --year 2025
Ausgabe:
Generating reports for 2024 (State: BY)...
Checking ArbZG compliance...
5 days with violations (7 total violations)
Generating real report...
-> /output/real/Arbeitszeitnachweis_2024_real.xlsx
...
Year overtime: +42.50h | Cumulative: +42.50h
Generating reports for 2025 (State: BY)...
Carry-over from prior years: +42.50h
Vacation carryover from previous year: 3 days
Checking ArbZG compliance...
12 days with violations (15 total violations)
...
Year overtime: -12.30h | Cumulative: +30.20h
Done.
Die Dateien liegen danach unter:
./output/real/Arbeitszeitnachweis_YYYY_real.xlsx./output/office/Arbeitszeitnachweis_YYYY.xlsxcheck - ArbZG-Compliance prüfenZeigt alle ArbZG-Verstöße ohne Excel zu generieren:
docker exec overtime-report python3 /app/main.py check --year 2025
Ausgabe:
ArbZG Check for 2025 (Marcus Pauli):
============================================================
26.04.2025 (11.1h): §3 >10h (11.1h)
25.06.2025 (23.3h): §3 >10h (23.3h), §5 Ruhezeit (3.2h < 11h)
...
Summary (12 days with violations):
§3 >10h: 8x
§4 Pause: 3x
§5 Ruhezeit: 2x
§9 Sonntag: 2x
send-email - Monats-E-Mail sendenSendet den Arbeitszeitnachweis per E-Mail:
# Vormonat automatisch
docker exec overtime-report python3 /app/main.py send-email
# Bestimmter Monat
docker exec overtime-report python3 /app/main.py send-email --year 2025 --month 6
# Test-Mail (an sich selbst)
docker exec overtime-report python3 /app/main.py send-email --test
Ein Sheet pro Monat + Zusammenfassungs-Sheet.
Monats-Sheet:

| Spalte | Inhalt |
|---|---|
| Datum | TT.MM.JJJJ |
| Tag | Mo, Di, Mi, … |
| Typ | Arbeit, Urlaub, Krank, Gleittag, Feiertag, Samstag, Sonntag |
| Projekt | Solidtime-Projektname(n) |
| Beschreibung | Solidtime-Beschreibung(en) |
| Ist (h) | Tatsächliche Stunden |
| Soll (h) | Vertragliche Stunden (nur bis Stichtag) |
| ArbZG | OK / §3 >10h / §4 Pause / §5 Ruhezeit / §9 Sonntag |
Farbcodierung:
Zusammenfassung mit ArbZG-Verstößen:

Ein Sheet pro Monat + Zusammenfassungs-Sheet mit Urlaubskonto.
Monats-Sheet:

| Spalte | Inhalt |
|---|---|
| Datum | TT.MM.JJJJ |
| Tag | Mo, Di, Mi, … |
| Typ | Arbeit, Urlaub, Krank, Gleittag, Feiertag, Samstag, Sonntag |
| Beginn | Fiktive Startzeit (08:00) |
| Ende | Berechnete Endzeit |
| Pause (min) | 0/30/45 je nach Stunden |
| Ist (h) | Korrigierte Stunden (max 10h) |
| Soll (h) | Vertragliche Stunden (nur bis Stichtag) |
Keine Projektnamen oder Beschreibungen in dieser Version.
Beide Versionen enthalten ein Zusammenfassungs-Sheet:

Inhalte:
START_DATE, nur wenn ungleich 0)Der Container führt automatisch folgende Cron-Jobs aus:
| Zeitpunkt | Aktion |
|---|---|
| Täglich 06:00 | Berichte generieren |
| Täglich 06:05 | Büro-Version zu Google Drive synchronisieren |
| 1. jedes Monats 07:00 | Monats-E-Mail senden |
docker exec overtime-report cat /var/log/overtime-report.log
Bearbeite die Datei crontab und baue den Container neu:
nano crontab
docker compose up -d --build
Die Jahressumme ist identisch. Monatlich kann es Abweichungen geben, weil Wochenend-/Feiertagsstunden auf den nächsten Werktag verschoben werden - auch über Monatsgrenzen hinweg.
Das Tool erkennt automatisch Solidtime-Projekte mit den Namen “Urlaub”, “Krank” oder “Gleittag” und markiert die Tage entsprechend. Für diese Tage gilt: Ist = Soll = hours_per_day (z.B. 7,8h bei einer 39h-Woche). Damit haben Krankheits- und Urlaubstage keinen Einfluss auf das Überstundenkonto — sie werden als bezahlte Abwesenheit (Entgeltfortzahlung) behandelt.
In der Büro-Version werden dafür fiktive Arbeitszeiten generiert (z.B. 08:00–15:48 bei 7,8h).
Siehe Berechnungslogik für Details und Beispielrechnungen.
Ja. Ohne --year generiert das Tool automatisch alle Jahre seit START_DATE mit kumulativem Überstundenübertrag:
docker exec overtime-report python3 /app/main.py generate
Jedes Jahr erhält den korrekten Übertrag aus den Vorjahren. Die Berichte werden in der Reihenfolge START_DATE.year bis zum aktuellen Jahr erstellt.
Standardmäßig werden alle Zeiteinträge über alle Solidtime-Clients hinweg gezählt. Das bedeutet: Arbeit für den Hauptarbeitgeber, Nebentätigkeiten bei anderen Kunden (z.B. HDBW) und Freistellungen (z.B. THW an Werktagen) fließen alle in das Überstundenkonto ein.
Mit EXCLUDE_CLIENTS kannst du bestimmte Clients komplett ausschließen (z.B. private Projekte). Mit THW_CLIENT_ID kannst du ehrenamtliche Wochenendarbeit ausschließen, während Werktags-Einträge als Freistellung zählen.
Siehe Berechnungslogik für Details.
Das ist die Summe aller Überstunden aus den Jahren vor dem aktuellen Berichtsjahr (seit START_DATE). Zusammen mit den Überstunden des aktuellen Jahres ergibt sich das Gesamtkonto. So geht nichts verloren, wenn ein neues Jahr beginnt.
Das aktuelle Jahr wird nur bis zum heutigen Tag berechnet (Stichtag). Zukünftige Tage haben Soll = 0, damit keine falschen Minusstunden entstehen. Das Stichtag-Datum steht als “Stand: TT.MM.JJJJ” im Zusammenfassungs-Sheet.
Wenn eine Urlaubsperiode im Dezember beginnt und im Januar fortgesetzt wird, zählen die Januar-Tage gegen den Urlaubsanspruch des Vorjahres — nicht des neuen Jahres. So wird der Resturlaub korrekt berechnet.
Beispiel: Urlaub vom 31.12.2025 bis 05.01.2026 → Die 2 Werktage im Januar 2026 (2. und 5. Jan) zählen als Urlaub 2025. Das 2026er Urlaubskonto bleibt bei 30 Tagen.
Beide Container müssen im selben Docker-Netzwerk sein. Prüfe:
docker network inspect solidtime_internal
Siehe Administratorhandbuch für Details.
Die Pausenzeiten sind fiktiv und werden nach ArbZG-Mindestvorgaben berechnet:
Die reale Version prüft deine tatsächlichen Pausen (Lücken zwischen Solidtime-Einträgen). Wenn du pro Tag nur einen durchgehenden Eintrag buchst, wird keine Pausenprüfung durchgeführt — denn ohne Lücken zwischen Einträgen ist eine Messung nicht möglich.